কানেক্টিভিটি ম্যানেজ.আরসিএনএনসিটিভিটি_এ্যাকশন অবমূল্যায়ন


95

অ্যান্ড্রয়েড এন-তে, অফিসিয়াল ওয়েবসাইটে উল্লেখ করা হয়েছে যে "অ্যান্ড্রয়েড এনকে লক্ষ্যযুক্ত অ্যাপ্লিকেশনগুলি সংযুক্তি_আ্যাকশন সম্প্রচারগুলি গ্রহণ করে না"। এবং এটি JobSchedulerবিকল্প হিসাবে ব্যবহার করা যেতে পারে যে উল্লেখ করা হয়েছে । কিন্তু সম্প্রচারের JobSchedulerমতো ঠিক একই আচরণ দেয় না CONNECTIVITY_ACTION

আমার অ্যান্ড্রয়েড অ্যাপ্লিকেশনটিতে, আমি এই সম্প্রচারটি ডিভাইসের নেটওয়ার্কের অবস্থা জানতে ব্যবহার করছিলাম। আমি জানতে চেয়েছিলাম এই রাজ্যটি ছিল CONNECTINGবা সম্প্রচারের CONNECTEDসহায়তায় CONNECTIVITY_ACTIONএবং এটি আমার প্রয়োজনের জন্য সবচেয়ে উপযুক্ত।

এখন এটি অবহেলা করা হয়েছে, কেউ আমাকে বর্তমান নেটওয়ার্কের অবস্থা পেতে বিকল্প পদ্ধতির পরামর্শ দিতে পারে?


10
এবং যদি ওপি কোনও দিন এমন কিছু আচরণ চায় যা এর targetSdkVersionজন্য এন বা তারপরে আপ করা দরকার ?
মাইকেল 10

4
ঠিক আছে, আমিও জানি যে আমি যদি অ্যান্ড্রয়েড এনআইয়ের সাথে আমার অ্যাপ্লিকেশনটিকে টার্গেট না করি তবে সম্প্রচারটি পাবেন। তবে আমার অ্যাপ্লিকেশনটির অ্যান্ড্রয়েড এন সমর্থন করা প্রয়োজন আমি কীভাবে অ্যান্ড্রয়েড এন এ একই সম্প্রচার আচরণ পেতে পারি? আমি চেষ্টা করতে পারেন অন্য কোন পদ্ধতির আছে? @ ডেভিডওয়াসার
রঘুরাম ডিবি

কখনও কখনও আমি মনে করি এটি ভবিষ্যতে ভবিষ্যতের বিষয়ে আরও বোধ তৈরি করে। এটি প্রোগ্রামিংয়ের জন্য বিশুদ্ধভাবে একটি বাস্তববাদী পদ্ধতির। অবশ্যই, আপনি সর্বদা এটি নিশ্চিত করার চেষ্টা করতে পারেন যে আপনার কোডটি কোনও হ্রাসপ্রাপ্ত বৈশিষ্ট্য ব্যবহার করে না। অন্যদিকে, অবহেলিত বৈশিষ্ট্যগুলি সাধারণত দীর্ঘ সময় ধরে থাকে এবং হ্রাসযোগ্য বৈশিষ্ট্যগুলি চলে যাওয়ার আগে এটি হতে পারে আপনার অ্যাপ্লিকেশন শেষের দিকে থাকবে। অ্যান্ড্রয়েড এন এতটাই নতুন যে আমি এটি নিয়ে উদ্বিগ্ন হয়ে বেশি সময় ব্যয় করব না। এখনো. শুধু আমার 2 সেন্ট। দয়া করে নোট করুন যে আমি প্রশ্নটিতে একটি মন্তব্য লিখেছি এবং "এমনটি করি না" একটি বৈধ উত্তর ছিল এমন পরামর্শ দেয়নি।
ডেভিড ওয়াসার

4
@ রঘুরামডবি আপনার অ্যাপটি অ্যান্ড্রয়েড এন এ চলতে পারে এমনকি আপনি যদি নিজের অ্যাপটি অ্যান্ড্রয়েড এনকে লক্ষ্য না করে থাকেন তবে আপনি কেবল অ্যান্ড্রয়েড এনকেই টার্গেট করতে হবে যদি আপনি কেবল অ্যান্ড্রয়েড এন তে উপলব্ধ বৈশিষ্ট্যগুলি ব্যবহার করতে চান তবে
ডেভিড ওয়াসার

4
আপনি এখনও ব্যবহার করতে পারেন BroadcastReceiverসঙ্গে android.net.conn.CONNECTIVITY_CHANGEঅভিপ্রায় ফিল্টার এমনকি যখন API29 লক্ষ্য করে, আপনি শুধু এটা রেজিস্টার করতে হবে Application.OnCreate। অ্যাপটি বন্ধ হয়ে গেলে আপনি কোনও আপডেট পাবেন না।
পিয়েরে

উত্তর:


101

যেটি হ্রাস করা হবে তা হ'ল ব্যাকগ্রাউন্ড অ্যাপ্লিকেশনটির নেটওয়ার্ক সংযোগের স্থিতির পরিবর্তনগুলি গ্রহণ করার ক্ষমতা।

ডেভিড ওয়াসার যেমন বলেছেন যে আপনি যদি অ্যাপের উপাদানটি ইনস্ট্যান্ট করা হয় (ধ্বংস হয় না) তবে আপনি সংযোগের পরিবর্তনের বিষয়ে অবহিত হতে পারেন এবং আপনি ম্যানিফেস্টে না গিয়ে এর প্রসংগের সাথে আপনার রিসিভারটিকে প্রোগ্রামিকভাবে নিবন্ধভুক্ত করেছেন।

অথবা আপনি তার পরিবর্তে নেটওয়ার্কক্যালব্যাক ব্যবহার করতে পারেন । বিশেষত, সংযুক্ত রাষ্ট্রের পরিবর্তনের জন্য আপনাকে ওভারলাইডের প্রয়োজন হবে to

আমাকে দ্রুত একটি স্নিপেট খসড়া করতে দিন:

public class ConnectionStateMonitor extends NetworkCallback {

   final NetworkRequest networkRequest;

   public ConnectionStateMonitor() {
       networkRequest = new NetworkRequest.Builder()
           .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
           .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
           .build();
   }

   public void enable(Context context) {
       ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
       connectivityManager.registerNetworkCallback(networkRequest, this);
   }

   // Likewise, you can have a disable method that simply calls ConnectivityManager.unregisterNetworkCallback(NetworkCallback) too.

   @Override
   public void onAvailable(Network network) {
       // Do what you need to do here
   }
}

4
যেহেতু এই কৌশলটি কেবলমাত্র কাজ করতে সক্ষম হবে, যদি অ্যাপ্লিকেশনটি অগ্রভাগে চলছে। তার মানে কি, যখন অ্যাপ্লিকেশনটি পূর্বগ্রাউন্ডে চলছে না, তখন আমরা সংযোগ ইভেন্ট শোনার ক্ষমতা রাখি না? রয়ে <কর্ম android: নাম = "android.net.conn.CONNECTIVITY_CHANGE" /> manifest.xml আর Android এন কোনো প্রভাব রয়েছে এ
Cheok ইয়ান চেঙ

4
পছন্দ করুন সংযোগ ইভেন্টগুলি শোনার জন্য আপনার কাছে এমন একটি প্রক্রিয়া থাকা দরকার যা অগ্রভাগে চলে। দেখে মনে হচ্ছে অ্যান্ড্রয়েড ফ্রেমওয়ার্ক ইঞ্জিনিয়ারদের দ্বারা যে অনুমানটি করা হয়েছিল তা হ'ল সংযোগ ইভেন্টগুলি শোনার বিষয়টি ক্লায়েন্ট এবং সার্ভারের মধ্যে কখন ডেটা সিঙ্ক করা শুরু করবেন তা জানার জন্য করা হয়েছিল। সুতরাং, জবশেডুলার সেই ব্যবহারের ক্ষেত্রে প্রস্তাবিত উপায় recommended
আমোক্রেন চেন্তির

28
হ্যাঁ কী, আরও 10 টি অ্যান্ড্রয়েড আপডেট এবং আমরা যা লিখতে সক্ষম হব সেগুলি হ্যালো ওয়ার্ল্ড অ্যাপ্লিকেশন
ডেনিসভিএ

4
আমার কি নেটওয়ার্কক্যালব্যাকটি নিবন্ধন করা প্রয়োজন (উদাহরণস্বরূপ, ক্রিয়াকলাপের অনডাস্ট্রয়ে পদ্ধতিতে)?
রুসলান বেরোজভ

4
@ রুসলান হ্যাঁ অবশ্যই, অথবা আপনি যা যা নিবন্ধিত হয়েছে তা ফাঁস করবেন
ডেনিসভিএ

35

আমি লিঙ্ক Sayem'sইস্যুগুলি এটি দেখানোর জন্য উত্তর আপডেট করব ।

class ConnectionLiveData(val context: Context) : LiveData<Boolean>() {

    private var connectivityManager: ConnectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager

    private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback

    private val networkRequestBuilder: NetworkRequest.Builder = NetworkRequest.Builder()
        .addTransportType(android.net.NetworkCapabilities.TRANSPORT_CELLULAR)
        .addTransportType(android.net.NetworkCapabilities.TRANSPORT_WIFI)

    override fun onActive() {
        super.onActive()
        updateConnection()
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(getConnectivityMarshmallowManagerCallback())
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> marshmallowNetworkAvailableRequest()
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> lollipopNetworkAvailableRequest()
            else -> {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    context.registerReceiver(networkReceiver, IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")) // android.net.ConnectivityManager.CONNECTIVITY_ACTION
                }
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager.unregisterNetworkCallback(connectivityManagerCallback)
        } else {
            context.unregisterReceiver(networkReceiver)
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private fun lollipopNetworkAvailableRequest() {
        connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityLollipopManagerCallback())
    }

    @TargetApi(Build.VERSION_CODES.M)
    private fun marshmallowNetworkAvailableRequest() {
    connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityMarshmallowManagerCallback())
    }

    private fun getConnectivityLollipopManagerCallback(): ConnectivityManager.NetworkCallback {
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
           connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
               override fun onAvailable(network: Network?) {
                   postValue(true)
               }

               override fun onLost(network: Network?) {
                   postValue(false)
               }
           }
           return connectivityManagerCallback
       } else {
           throw IllegalAccessError("Accessing wrong API version")
       }
    }

    private fun getConnectivityMarshmallowManagerCallback(): ConnectivityManager.NetworkCallback {
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
            override fun onCapabilitiesChanged(network: Network?, networkCapabilities: NetworkCapabilities?) {
                networkCapabilities?.let { capabilities ->
                    if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                        postValue(true)
                    }
                }
            }
            override fun onLost(network: Network?) {
                postValue(false)
            }
        }
        return connectivityManagerCallback
    } else {
        throw IllegalAccessError("Accessing wrong API version")
    }

    private val networkReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            updateConnection()
        }
    }

    private fun updateConnection() {
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        postValue(activeNetwork?.isConnected == true)
    }
}

এবং একই ব্যবহার:

    val connectionLiveData = ConnectionLiveData(context)
        connectionLiveData.observe(this, Observer { isConnected ->
           isConnected?.let {
             // do job
           }
    })

বিটিডব্লিউ সায়েম আপনার সমাধানের জন্য ধন্যবাদ।


4
আশ্চর্য সমাধান!
বক্স

4
লাইভ ডেটা ব্যবহার এবং পুরানো সংস্করণকে সমর্থন করার জন্য খুব ভাল সমাধান
প্রকাশ শুক্লা

এটি ইন্টারনেটে উপলব্ধ সেরা সমাধান।
করণ শর্মা

খুব ভাল সমাধান! তবে একটি "নেই" রয়েছে - এটি উপলভ্য (নেটওয়ার্ক: নেটওয়ার্ক?) পদ্ধতিটি ব্যবহার করার জন্য ভুল উপায়, কারণ এটি এমনকি ইন্টারনেট উপলব্ধ নয় বলেও অনুরোধ করে। অন্যাপিপ্যাবিলিটিস চেঞ্জড (নেটওয়ার্ক: নেটওয়ার্ক, নেটওয়ার্ককিপ্যাবিলিটিস: নেটওয়ার্ককিপ্যাবিলিটিস) এবং নেটওয়ার্কক্যাপাবিলিটিগুলি পরীক্ষা করুন (এনইএসপ্যাবিলিটিঅনটারনেট) এবং নেটওয়ার্ককাপাবিলিটিস (এনইএসসিএপিএবিএবিএলএটি (NET_CAPABILITY_VALIDATED) to
দিমিত্রিকানুন্নিকফ

এই কোড বেসের মধ্যে আইপি এবং নেটওয়ার্ক টাইপ কীভাবে পাবেন?
এআরমাস

29

অ্যান্ড্রয়েড এন এর জন্য ডকুমেন্টেশন বলে:

অ্যান্ড্রয়েড এনকে লক্ষ্যযুক্ত অ্যাপ্লিকেশনগুলি এই ইভেন্টগুলির বিজ্ঞপ্তির জন্য অনুরোধ জানাতে ম্যানিফেস্ট এন্ট্রি থাকলেও CONNECTIVITY_ACTION সম্প্রচারগুলি গ্রহণ করে না। অগ্রভাগে চলমান অ্যাপ্লিকেশনগুলি এখনও যদি ব্রডকাস্টার্সিভারের সাথে বিজ্ঞপ্তির জন্য অনুরোধ করে তবে তাদের মূল থ্রেডে তারা CONNECTIVITY_CHANGE শুনবে can

এর অর্থ হল যে আপনার BroadcastReceiverসংযোগটি নেটওয়ার্ক সংযোগের পরিবর্তনগুলি সনাক্ত করতে যদি আপনার অ্যাপ্লিকেশনটি অগ্রভাগে চলমান থাকে তবে আপনি এখনও একটি নিবন্ধভুক্ত করতে পারেন ।


চমৎকার সূক্ষ্ম ক্যাচ :)
আমোক্রেন চেন্তির

এর অর্থ কি এই যে পূর্ববর্তী স্থানে না থাকলে অ্যাপটি সম্প্রচার গ্রহণ বন্ধ করে দেবে? (সুতরাং আমি উদাহরণের জন্য কোনও পরিষেবাতে এটি শুনতে পারি না?)
রবিবার

4
আমি নিশ্চিতভাবে জানি না, এটি নিশ্চিত হওয়ার জন্য আমার এটি পরীক্ষা করা দরকার। তবে, ডকুমেন্টেশনটি পড়লে মনে হবে আপনার অ্যাপটি যদি অগ্রভাগে না থাকে তবে আপনি সম্প্রচারটি পাবেন না Intent
ডেভিড ওয়াসার

4
তবে যে কোনও সিপ-অ্যাপস (ভিওআইপি) এর জন্য ব্যাকগ্রাউন্ডে সংযোগের পরিবর্তনটি সনাক্ত করা বাধ্যতামূলক ... এই অ্যাপ্লিকেশনগুলি সাধারণত কয়েক দিনের জন্য পটভূমিতে চলমান থাকে এবং কেবলমাত্র কোনও কল আসে (ফোনের ডায়ালারের মতো) কেবল তখনই অগ্রভাগে চলে যায় .. এই অ্যাপ্লিকেশনগুলির পটভূমিতে স্বয়ংক্রিয়ভাবে পুনরায় সংযোগ স্থাপন করা দরকার । এটি অ্যান্ড্রয়েড প্ল্যাটফর্ম থেকে এই সমস্ত অ্যাপ্লিকেশনগুলিকে (যার নিজস্ব ধাক্কা সার্ভার নেই) হত্যা করে কারণ তারা অফলাইনে থাকবে। সর্বদা.
গ্রিসগ্রাম

শুধু ফায়ারবেস পুশ পরিষেবা ব্যবহার করুন।
পিয়েরে

21

অ্যান্ড্রয়েড এন সমর্থনের জন্য দয়া করে প্রথমে @ আমোক্রেন চেনটিয়ার উত্তরটি দেখুন।

যারা সমস্ত এপিআই স্তরে সমর্থন করতে চায় এবং এটি ইউআইতে পর্যবেক্ষণ করতে চায় তাদের জন্য দয়া করে বেলো কোডটি পরীক্ষা করুন।

নেটওয়ার্ক সংযোগের লাইভ ডেটা:

class ConnectionLiveData(val context: Context) : LiveData<Boolean>(){

    var  intentFilter = IntentFilter(CONNECTIVITY_ACTION)
    private var  connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    private lateinit var networkCallback : NetworkCallback

    init {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            networkCallback = NetworkCallback(this)
        }
    }

    override fun onActive() {
        super.onActive()
        updateConnection()
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(networkCallback)
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
                val builder = NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
                connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
            }
            else -> {
                context.registerReceiver(networkReceiver, intentFilter)
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager.unregisterNetworkCallback(networkCallback)
        } else{
            context.unregisterReceiver(networkReceiver)
        }
    }


    private val networkReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            updateConnection()
        }
    }

    fun updateConnection() {
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        postValue(activeNetwork?.isConnectedOrConnecting == true)
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    class NetworkCallback(val liveData : ConnectionLiveData) : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network?) {
            liveData.postValue(true)
        }

        override fun onLost(network: Network?) {
            liveData.postValue(false)
        }
    }
}

ইউআইতে পর্যবেক্ষণ করুন (ক্রিয়াকলাপ / টুকরা):

val connectionLiveData = ConnectionLiveData(context)
    connectionLiveData.observe(this, Observer { 
       // do whatever you want with network connectivity change 
})

বিটিডব্লিউ, আপনার IntentFilterস্পষ্টভাবে সংজ্ঞা দেওয়ার দরকার নেই । ভালো লেগেছে:var intentFilter = IntentFilter(CONNECTIVITY_ACTION)
রায়ান অমরাল

আপনার পরামর্শের জন্য ধন্যবাদ. আমি অনলাইনে প্রতিবার অবজেক্ট তৈরি করতে চাইনি।
সায়েম

আমি বলতে চাইছি যে 2 গ্লোবাল ভেরিয়েবল / বৈশিষ্ট্য ( intentFilterএবং connectivityManager) আপনার স্পষ্টভাবে তাদের ধরণের ( IntentFilterএবং ConnectivityManagerযথাক্রমে) সংজ্ঞা দেওয়ার দরকার নেই ।
রায়ান অমরাল

বেশিরভাগ স্টাফটি (দুর্ভাগ্যক্রমে) হ্রাস করা হয় ..
এন্ড্রু

7

আমি কয়েক দিন আগে একই সমস্যায় পড়েছিলাম এবং আমি এই লাইব্রেরিটি অ্যান্ড্রয়েড-জব ব্যবহার করার সিদ্ধান্ত নিয়েছি

এই লাইব্রেরি ব্যবহার JobSchedular, GcmNetworkManagerএবং BroadcastReceiverযা Android সংস্করণ উপর নির্ভর করে অ্যাপ্লিকেশন চলমান আছে।

একটি কাজ শুরু মোটামুটি সহজ

new JobRequest.Builder(DemoSyncJob.TAG)
            .setRequiresCharging(true)
            .setRequiresDeviceIdle(false)
            .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) // this is what gets the job done
            .build()
            .schedule();

4
আমি একই সময়সূচীর চেষ্টা করেছি এবং এর মতো ব্যতিক্রম পেয়েছি আপনি কোনও বাধা ছাড়াই একটি চাকরী গড়ার চেষ্টা করছেন, এটি অনুমোদিত নয়। আপনি কি দয়া করে আমাদের এটি সমাধান করতে সহায়তা করতে পারেন ??
সংকেত কচেলা

এই উদ্দেশ্যে অ্যান্ড্রয়েড-জব ব্যবহার করা খুব ভাল সমাধান নয়। এটি নির্দিষ্ট সময় জিনিসগুলি একবার বা পর্যায়ক্রমে চালানো বোঝানো হয়। এটি বিপদাশঙ্কা এবং এই জাতীয়গুলির জন্য retro- সামঞ্জস্যতা সমর্থন আনার উদ্দেশ্যে। এটি কেন এপিআই পরিবর্তিত হয়েছে এবং পড়ার পুরো ধারণাটির বিপরীতে যায়: developer.android.com/training/mon څارি- ডিভাইস- স্টেট/… আপনি কী কারণে তাড়াতাড়ি উপলব্ধি করতে পারেন।
পেড্রনোলোসো

কেবলমাত্র সমস্যাটি হ'ল অ্যান্ড্রয়েড এন এ ভবিষ্যতে কেবল সর্বনিম্ন 15 মিনিটের জন্য নির্ধারিত হতে পারে
ফায়ার ক্র

4

আমি একটি কোটলিন বাস্তবায়ন লিখেছি যা সিয়ামের উত্তরের ভিত্তিতে তবে তা ছাড়াই LiveData। আমি সিদ্ধান্ত নিয়েছি (সময়ে এই সময়ে) সর্বশেষ এপিআই পদ্ধতি ( ConnectivityManager#registerDefaultNetworkCallback) যা অ্যান্ড্রয়েড নুগ্যাটকে লক্ষ্য করে।

/**
 * Observes network connectivity by consulting the [ConnectivityManager].
 * Observing can run infinitely or automatically be stopped after the first response is received.
 */
class ConnectivityObserver @JvmOverloads constructor(

        val context: Context,
        val onConnectionAvailable: () -> Unit,
        val onConnectionLost: () -> Unit = {},
        val shouldStopAfterFirstResponse: Boolean = false

) {

    private val connectivityManager
        get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    @Suppress("DEPRECATION")
    private val intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)

    private val broadCastReceiver = object : BroadcastReceiver() {

        @Suppress("DEPRECATION")
        override fun onReceive(context: Context?, intent: Intent?) {
            if (ConnectivityManager.CONNECTIVITY_ACTION != intent?.action) {
                return
            }
            val networkInfo = connectivityManager.activeNetworkInfo
            if (networkInfo != null && networkInfo.isConnectedOrConnecting) {
                onConnectionAvailable.invoke()
            } else {
                onConnectionLost.invoke()
            }
            if (shouldStopAfterFirstResponse) {
                stop()
            }
        }

    }

    private lateinit var networkCallback: ConnectivityManager.NetworkCallback

    init {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            networkCallback = object : ConnectivityManager.NetworkCallback() {

                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    onConnectionAvailable.invoke()
                    if (shouldStopAfterFirstResponse) {
                        stop()
                    }
                }

                override fun onLost(network: Network?) {
                    super.onLost(network)
                    onConnectionLost.invoke()
                    if (shouldStopAfterFirstResponse) {
                        stop()
                    }
                }
            }
        }
    }

    fun start() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            // Decouple from component lifecycle, use application context.
            // See: https://developer.android.com/reference/android/content/Context.html#getApplicationContext()
            context.applicationContext.registerReceiver(broadCastReceiver, intentFilter)
        } else {
            connectivityManager.registerDefaultNetworkCallback(networkCallback)
        }
    }

    fun stop() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            context.applicationContext.unregisterReceiver(broadCastReceiver)
        } else {
            connectivityManager.unregisterNetworkCallback(networkCallback)
        }
    }

}

ব্যবহার:

val onConnectionAvailable = TODO()
val connectivityObserver = ConnectivityObserver(context, onConnectionAvailable)
connectivityObserver.start()
connectivityObserver.stop()

বা:

val onConnectionAvailable = TODO()
val onConnectionLost = TODO()
ConnectivityObserver(context, 
    onConnectionAvailable, 
    onConnectionLost, 
    shouldStopAfterFirstResponse = true
).start()

ACCESS_NETWORK_STATEআপনার AndroidManLive.xML এ অনুমতি যুক্ত করতে ভুলবেন না :

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

আমি আপনার কাছ থেকে সহায়ক মন্তব্য এবং উন্নতি পড়ার প্রত্যাশায় রয়েছি।


4
মূল থ্রেডের একটি ক্রিয়াকলাপে (প্রসঙ্গে) "স্পর্শ দর্শন" করতে সক্ষম হবার জন্য আমাকে কলব্যাকের জন্য কিছু পরিবর্তন করতে হয়েছিল: (context as AppCompatActivity).runOnUiThread(object: Runnable{ override fun run() { onConnectionAvailable.invoke() } })পরিবর্তে onConnectionAvailable.invoke()। একই জন্য onConnectionLost.invoke()
Воробьев Воробьев

হ্যাঁ, আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে আপনার থ্রেডগুলি পরিবর্তন করতে পারে। আমি এটিকে ক্লাসের অংশ হিসাবে তৈরি করব না বরং পরিবর্তে শ্রেণীর গ্রাহকরা এটির যত্ন নিতে দিন। তবে ইঙ্গিতটির জন্য আপনাকে ধন্যবাদ।
জেজেডি

4

@ কাবাব ক্রাব্বির উত্তরের ভিত্তিতে:

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.CONNECTIVITY_ACTION
import android.net.ConnectivityManager.EXTRA_NO_CONNECTIVITY
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.os.Build
import androidx.lifecycle.LiveData

class ConnectivityWatcher(
    private val context: Context
): LiveData<Boolean>() {

    private lateinit var networkCallback: ConnectivityManager.NetworkCallback
    private lateinit var broadcastReceiver: BroadcastReceiver

    override fun onActive() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            networkCallback = createNetworkCallback()
            cm.registerDefaultNetworkCallback(networkCallback)
        } else {
            val intentFilter = IntentFilter(CONNECTIVITY_ACTION)
            broadcastReceiver = createBroadcastReceiver()
            context.registerReceiver(broadcastReceiver, intentFilter)
        }
    }

    override fun onInactive() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            cm.unregisterNetworkCallback(networkCallback)
        } else {
            context.unregisterReceiver(broadcastReceiver)
        }
    }

    private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {

        override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
        ) {
            val isInternet = networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)
            val isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)
            postValue(isInternet && isValidated)
        }

        override fun onLost(network: Network) {
            postValue(false)
        }
    }

    private fun createBroadcastReceiver() = object : BroadcastReceiver() {

        override fun onReceive(context: Context?, intent: Intent?) {
            val isNoConnectivity = intent?.extras?.getBoolean(EXTRA_NO_CONNECTIVITY) ?: true
            postValue(!isNoConnectivity)
        }
    }
}

এবং এটির মূল উত্তরের মতো প্রায় একই ব্যবহার (উদাহরণস্বরূপ যদি কোনও ক্রিয়াকলাপ থেকে পর্যবেক্ষণ করা হয়):

ConnectivityWatcher(this).observe(this, Observer {
    Log.i("*-*-*", "is internet available? - ${if (it) "Yes" else "No"}")
})

2

অ্যান্ড্রয়েড এন (নওগ্যাট) লক্ষ্যযুক্ত অ্যাপ্লিকেশনগুলি CONNECTIVITY_ACTIONম্যানিফেস্টে সংজ্ঞায়িত সম্প্রচারগুলি গ্রহণ করে না ( স্বেল্ট দেখুন )।

সম্ভাব্য সমাধান:

  • ConnectivityManager.registernetworkCallback()একবার অ্যাপ্লিকেশন চলার সাথে স্পষ্টভাবে একটি নেটওয়ার্ক কলব্যাক নিবন্ধন করুন ।
  • একটি ব্যবহার করুন JobSchedulerএবং এর মাধ্যমে একটি অপরিশোধিত নেটওয়ার্ক নির্দিষ্ট করুন setRequiredNetworkType()

এছাড়াও অ্যান্ড্রয়েড ও - পটভূমিতে সংযোগের পরিবর্তন সনাক্ত করুন See


1

আমি উত্তর সাথে একমত @rds এর প্রস্তাবিত

মনে রাখবেন যে CONNECTIVITY_ACTION এপিআই স্তরের 28 স্তরে অবনতি হয়েছে।

যদি আপনার প্রয়োজনীয়তা থাকে যে অ্যাপ্লিকেশনটি হত্যা করা সত্ত্বেও ওয়াইফাই রাষ্ট্র (সংযোগ / সংযোগ বিচ্ছিন্ন) সনাক্ত করা উচিত এবং আপনি সর্বশেষ সংস্করণটি লক্ষ্য করতে চান তবে আপনার খুব পছন্দ নেই have

আপনার ব্যবহার করা দরকার connectivityManager.registerNetworkCallback(networkRequest, networkCallback)

প্রশ্ন আপনি ব্রডকাস্টরিসিভার ব্যবহার করতে পারবেন না তবে কিভাবে?

আপনি যদি ওয়ার্কম্যানেজার (পর্যায়ক্রমিক অনুরোধ) ব্যবহার করেন তবে চাকরির জন্য বা আরও ভাল ব্যবহার করতে পারেন। পর্যায়ক্রমিক কেননা যদি এটি ওয়ানটাইমআরকিউয়েস্ট হয় তবে এটি কেবল একবার চালাতে সক্ষম হবে এবং আপনার অ্যাপ্লিকেশনটির অগ্রভাগে থাকা অবস্থায় শুনতে থাকবে।

ডকুমেন্টেশন বলে:

অ্যাপ্লিকেশনটি প্রস্থান না করা বা #unregisterNetworkCallback (নেটওয়ার্কক্যালব্যাক) লিঙ্ক না করা পর্যন্ত কলব্যাকগুলি কল করা অব্যাহত থাকবে।

একবার অ্যাপ্লিকেশনটিকে হত্যা করা বা সাম্প্রতিক অ্যাপ্লিকেশন তালিকা থেকে সরানো হলে, নেটওয়ার্কক্যালব্যাক শুনতে সক্ষম হবে না।

সুতরাং, অ্যাপটিকে অবিরাম শোনার জন্য আপনার এ জাতীয় পর্যায়ক্রমিক কাজের প্রয়োজন। সময়কাল কত হবে? এটি আপনার উপর নির্ভর করে এবং কেস কেস কেস নির্ভর করে।

আমি জানি এটি কিছুটা কুৎসিত উপায় তবে এটি এটির মতো। একটি চ্যালেঞ্জ হ'ল যদি ব্যবহারকারীর ডিভাইসটি ডোজে মোডে থাকে বা অ্যাপ্লিকেশনটি স্ট্যান্ডবাই রাজ্যে থাকে তবে আপনার কাজটি বিলম্ব হতে পারে।


এও মনে রাখবেন যে কিছু ভারি কাস্টমাইজড ইএমইউআই তে, এমআইইউআই অ্যান্ড্রয়েড ওএস ওয়ার্ক ম্যানেজার (পর্যায়ক্রমিক টাস্ক) সর্বদা সঠিকভাবে কাজ করে না।
কাবাব ক্রাবি

1

যখন আমরা registerNetworkCallbackপদ্ধতিটি ব্যবহার করে কোনও নেটওয়ার্ক কলব্যাক নিবন্ধভুক্ত করি তখন কখনও কখনও এটি ট্রিগার হয় না এবং কখনও কখনও এটি মিথ্যা-পজিটিভকে ট্রিগার করে:

  1. আমরা যদি ইন্টারনেট সংযোগ দিয়ে কোনও অ্যাপ্লিকেশন শুরু করি তবে onAvailableপদ্ধতিটি ট্রিগার হয়ে যায়।
  2. কিন্তু যখন আমরা কোনও অ্যাপ্লিকেশন শুরু করি তখন ডিভাইসে কোনও ইন্টারনেট সংযোগ না থাকলে এর কিছুই NetworkCallbackবলা হয় না (এটি পি। 1 এর কারণে খুব আশ্চর্যজনক)
  3. আমাদের যদি ওয়াইফাই সংযোগ থাকে তবে ইন্টারনেট সংযোগ onAvailableপদ্ধতি ছাড়াই ট্রিগার হয়। এবং আমি মনে করি এটি মিথ্যা-ইতিবাচক আচরণ কারণ আমরা ইন্টারনেট সংযোগটি পর্যবেক্ষণ আশা করি।

আপনি নীচের কোডটিতে দেখতে পাচ্ছেন ডিফল্টরূপে ইন্টারনেট সংযোগ উপলব্ধ এবং এটি পরিবর্তন হলেই এটি ট্রিগার করে। কোনও মিথ্যা-ইতিবাচক ট্রিগার নেই।

কেবলমাত্র এই এবং এই উত্তরগুলির সংক্ষিপ্তসার করুন (তবে কেবলমাত্র API এর জন্য> = 21):

class ConnectionManager @Inject constructor(
    private val connectivityManager: ConnectivityManager,
    private val disposable: CompositeDisposable,
    private val singleTransformer: SingleTransformer<*, *>
) : LiveData<Boolean>() {

    private var isNetworkAvailable = true

    private val builder = NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)

    private val callback = object : ConnectivityManager.NetworkCallback() {

        override fun onAvailable(network: Network) {
            ping()
        }

        override fun onLost(network: Network) {
            ping()
        }
    }

    private fun ping() {
        disposable.add(
            Single.fromCallable {
                try {
                    val timeoutMs = 1500
                    val socket = Socket()
                    val socketAddress = InetSocketAddress("8.8.8.8", 53)

                    socket.connect(socketAddress, timeoutMs)
                    socket.close()
                    true
                } catch (e: IOException) {
                    false
                }
            }
                .compose(singleTransformer as SingleTransformer<Boolean, Boolean>)
                .subscribeBy {
                    if (isNetworkAvailable != it){
                        value = it
                        isNetworkAvailable = it
                    }
                }
        )
    }

    override fun onActive() {
        ping()
        connectivityManager.registerNetworkCallback(builder.build(), callback)
    }

    override fun onInactive() {
        disposable.clear()
        connectivityManager.unregisterNetworkCallback(callback)
    }
}

নির্ভরতা কীভাবে সরবরাহ করবেন

@Provides
fun provideTransformer(): SingleTransformer<Boolean, Boolean> {
    return SingleTransformer<Boolean, Boolean> { upstream: Single<Boolean> ->
        upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
    }
}

@Singleton
@Provides
fun provideConnectivityManager(context: Context): ConnectivityManager =
        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

@Singleton
@Provides
fun provideConnectionManager(connectivityManager: ConnectivityManager, singleTransformer: SingleTransformer<Boolean, Boolean>): ConnectionManager =
        ConnectionManager(connectivityManager, singleTransformer)

এবং কীভাবে ব্যবহার করবেন:

@Inject
lateinit var connectionManager: ConnectionManager

//....

viewLifecycleOwner.observe(connectionManager) { isInternetAvailable ->
    // TODO 
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.