ConnectivityManager.CONNECTIVITY_ACTION पदावनत


94

एंड्रॉइड एन में, आधिकारिक वेबसाइट पर उल्लेख किया गया है कि "एंड्रॉइड एन को लक्षित करने वाले ऐप्स को CONNECTIVITY_ACTION प्रसारण नहीं मिलता है"। और यह भी उल्लेख है कि JobSchedulerएक विकल्प के रूप में इस्तेमाल किया जा सकता है। लेकिन प्रसारण JobSchedulerके समान व्यवहार प्रदान नहीं करता है CONNECTIVITY_ACTION

अपने Android एप्लिकेशन में, मैं डिवाइस के नेटवर्क स्थिति को जानने के लिए इस प्रसारण का उपयोग कर रहा था। मैं जानना चाहता था कि यह राज्य प्रसारण की मदद से था CONNECTINGया नहीं और यह मेरी आवश्यकता के लिए सबसे उपयुक्त था।CONNECTEDCONNECTIVITY_ACTION

अब जब यह पदावनत हो गया है, तो क्या कोई मुझे वर्तमान नेटवर्क स्थिति प्राप्त करने के लिए वैकल्पिक दृष्टिकोण सुझा सकता है?


10
और क्या होगा अगर किसी दिन ओपी किसी व्यवहार को चाहता है जिसे targetSdkVersionएन या बाद में उत्थान की आवश्यकता होती है ?
माइकल

1
वैसे, मुझे यह भी पता है कि अगर मैं अपने आवेदन को Android NI पर लक्षित नहीं करता तो प्रसारण प्राप्त होगा। लेकिन मेरे आवेदन को एंड्रॉइड एन का समर्थन करने की आवश्यकता है। मैं एंड्रॉइड एन में समान प्रसारण व्यवहार कैसे प्राप्त कर सकता हूं? क्या कोई और तरीका है जिसे मैं आज़मा सकता हूँ? @ डेविडविशर
रघुराम db

कभी-कभी मुझे लगता है कि यह भविष्य में भविष्य के बारे में अधिक समझ में आता है। यह विशुद्ध रूप से प्रोग्रामिंग के लिए एक व्यावहारिक दृष्टिकोण है। बेशक, आप हमेशा यह सुनिश्चित करने की कोशिश कर सकते हैं कि आपका कोड किसी भी पदावनत सुविधाओं का उपयोग नहीं करता है। दूसरी ओर, पदावनत सुविधाएँ आमतौर पर लंबे समय तक रहती हैं और यह हो सकता है कि पदावनत सुविधाओं के चले जाने से पहले ही आपका ऐप एंड-ऑफ हो जाएगा। Android N इतना नया है कि मैं इसके बारे में चिंता करने में बहुत समय नहीं लगाऊंगा। फिर भी। बस मेरे 2 सेंट। कृपया ध्यान दें कि मैंने प्रश्न के लिए एक टिप्पणी लिखी थी और यह सुझाव नहीं दिया था कि "ऐसा न करें" एक वैध उत्तर था।
डेविड वासर

2
@Raghuramdb आपका ऐप Android N पर चल सकता है, भले ही आप अपने ऐप को Android N पर लक्षित न करें। आपको केवल Android N को लक्षित करना होगा, यदि आप केवल Android N में उपलब्ध सुविधाओं का उपयोग करना चाहते हैं
डेविड वासर

2
API29 को टारगेट करते हुए भी आप आशय फ़िल्टर के BroadcastReceiverसाथ उपयोग कर सकते हैं android.net.conn.CONNECTIVITY_CHANGE, बस आपको इसे पंजीकृत करने की आवश्यकता है Application.OnCreate। ऐप के बंद होने पर आपको कोई अपडेट नहीं मिलेगा।
पियरे

जवाबों:


97

क्या होगा वंचित नेटवर्क कनेक्शन राज्य परिवर्तन प्राप्त करने के लिए एक पृष्ठभूमि वाले आवेदन की क्षमता है।

जैसा कि डेविड वासर ने कहा कि आप अभी भी कनेक्टिविटी परिवर्तनों की सूचना प्राप्त कर सकते हैं यदि ऐप घटक को त्वरित (नष्ट नहीं) किया गया है और आपने अपने रिसीवर को प्रोग्राम के रूप में अपने संदर्भ के साथ पंजीकृत किया है, बजाय इसे प्रकट में करने के।

या आप इसके बजाय NetworkCallback का उपयोग कर सकते हैं । विशेष रूप से, आपको कनेक्टेड राज्य परिवर्तनों के लिए onAvailable ओवरराइड करने की आवश्यकता होगी ।

मुझे जल्दी से एक स्निपेट का मसौदा तैयार करने दें:

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
   }
}

2
चूंकि यह तकनीक केवल तभी काम कर पाएगी, जब ऐप अग्रभूमि में चल रहा हो। क्या इसका मतलब है, हमारे पास अब कनेक्शन ईवेंट को सुनने की क्षमता नहीं है, जब ऐप अग्रभूमि में नहीं चल रहा है? होने के बाद <android: name = "android.net.conn.CONNECTIVITY_CHANGE" /> मेनिफ़ेस्ट।
xml का

2
@CheokYanCheng AFAIK यह सही है। कनेक्टिविटी इवेंट्स को सुनने के लिए आपके पास एक ऐसी प्रक्रिया होनी चाहिए जो अग्रभूमि में चलती हो। ऐसा लगता है कि एंड्रॉइड फ्रेमवर्क इंजीनियरों द्वारा बनाई गई धारणा यह थी कि क्लाइंट और सर्वर के बीच डेटा सिंक्रनाइज़ करना शुरू करने के लिए कनेक्टिविटी की घटनाओं को सुनने के लिए ज्यादातर यह जानने के लिए किया गया था। इसलिए, JobScheduler उस उपयोग के मामले के लिए अनुशंसित तरीका है।
अमोकेरेन चेंटिर 20


1
क्या मुझे नेटवर्ककॉलबैक को अपंजीकृत करने की आवश्यकता है (उदाहरण के लिए, गतिविधि के onDestroy विधि में)?
रुस्लान बिर्ज़ोव

2
@ रुस्लान हाँ, या आप जो कुछ भी पंजीकृत है, उसे लीक करेंगे
डेनिसवा

34

मैं इसे 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
           }
    })

आपके समाधान के लिए Btw धन्यवाद Sayem।


2
अद्भुत समाधान!
बॉक्स

2
लाइव डेटा और पुराने संस्करण का समर्थन करने के लिए बहुत अच्छा समाधान
प्रकाश शुक्ला

यह इंटरनेट पर उपलब्ध सबसे अच्छा समाधान है।
करण शर्मा

बहुत अच्छा समाधान! लेकिन वहाँ एक "नहीं" है - यह onAvailable (नेटवर्क: नेटवर्क?) विधि का उपयोग करने का गलत तरीका है, क्योंकि यह इंटरनेट भी उपलब्ध नहीं है। OnCapabilitiesChanged (नेटवर्क: नेटवर्क, नेटवर्क कैपेबिलिटीज: NetworkCapabilities) और नेटवर्क नेटवर्क चेकअप करें।
दिमित्रीकुननिकॉफ

इस कोड के आधार पर आईपी और नेटवर्क प्रकार कैसे प्राप्त करें?
a_rmas

28

Android N के लिए प्रलेखन:

Android N को लक्षित करने वाले ऐप्स को CONNECTIVITY_ACTION प्रसारण प्राप्त नहीं होता है, भले ही उनके पास इन घटनाओं की सूचना के लिए अनुरोध करने के लिए प्रविष्टियाँ हों। अग्रभूमि में चलने वाले ऐप्स अभी भी अपने मुख्य धागे पर CONNECTIVITY_CHANGE के लिए सुन सकते हैं यदि वे एक ब्रॉडकास्टर के साथ सूचना का अनुरोध करते हैं।

इसका मतलब है कि आप तब भी रजिस्टर कर सकते हैं BroadcastReceiverजब नेटवर्क कनेक्टिविटी में बदलाव का पता लगाने के लिए आपका ऐप अग्रभूमि में चल रहा हो।


अच्छा सूक्ष्म पकड़ :)
अमोकेरेन चेंटिर

क्या इसका मतलब यह है कि ऐप एक बार प्रसारण बंद कर देगा क्योंकि यह अग्रभूमि में नहीं है? (इसलिए मैं उदाहरण के लिए एक सेवा में इसके लिए नहीं सुन सकता?)
सूंडी

1
मुझे यकीन नहीं है, मुझे यकीन है कि यह परीक्षण करने की आवश्यकता होगी। हालाँकि, दस्तावेज़ पढ़ने से प्रतीत होगा कि यदि आपका ऐप अग्रभूमि में नहीं है, तो आपको प्रसारण नहीं मिलेगा Intent
डेविड वासर

2
लेकिन किसी भी सिप-एप्स (वीओआईपी) के लिए बैकग्राउंड में कनेक्टिविटी परिवर्तन अनिवार्य है ... उन एप्स को आम तौर पर दिनों के लिए बैकग्राउंड में चलाया जाता है और केवल एक फोन आने पर (फोन के अपने डायलर की तरह) फोरग्राउंड करने के लिए कूदते हैं। उन ऐप्स को पृष्ठभूमि में स्वचालित रूप से फिर से कनेक्ट करने की आवश्यकता होती है। यह उन सभी ऐप को मारता है, जो एंड्रॉइड प्लेटफॉर्म से अपने स्वयं के पुश सर्वर के रूप में नहीं हैं क्योंकि वे ऑफ़लाइन होंगे। हमेशा।
ग्रिस्ग्राम

बस firebase पुश सेवा का उपयोग करें।
पियरे

21

Android N समर्थन के लिए कृपया पहले @Amokrane Chentir उत्तर देखें।

उन सभी के लिए जो सभी एपीआई स्तर पर समर्थन करना चाहते हैं और इसे यूआई में देखना चाहते हैं, कृपया बलो कोड की जांच करें।

NetworkConnection का लाइव डेटा:

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)
        }
    }
}

UI में देखें (गतिविधि / टुकड़ा):

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

btw, आपको IntentFilterस्पष्ट रूप से परिभाषित करने की आवश्यकता नहीं है । जैसे:var intentFilter = IntentFilter(CONNECTIVITY_ACTION)
रायन अमर

तुम्हारे सुझाव के लिए धन्यवाद। मैं onActive में हर बार ऑब्जेक्ट बनाना नहीं चाहता था।
1

मेरा मतलब है कि 2 वैश्विक चर / गुण ( intentFilterऔर connectivityManager) आपको उनके प्रकार ( IntentFilterऔर ConnectivityManagerक्रमशः) को स्पष्ट रूप से परिभाषित करने की आवश्यकता नहीं है ।
रयान अमरल

7

मैं कुछ दिन पहले उसी समस्या में भाग गया था और मैंने इस लाइब्रेरी एंड्रॉइड-जॉब का उपयोग करने का फैसला किया

यह लाइब्रेरी उपयोग करती है JobSchedular, GcmNetworkManagerऔर यह BroadcastReceiverनिर्भर करता है कि ऐप किस एंड्रॉइड वर्जन पर चल रहा है।

नौकरी शुरू करना काफी आसान है

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

1
मैंने एक ही शेड्यूलर की कोशिश की है और इस तरह का अपवाद पा रहा है। आप बिना किसी बाधा के नौकरी बनाने की कोशिश कर रहे हैं, इसकी अनुमति नहीं है। क्या आप इसे हल करने में हमारी मदद कर सकते हैं ??
संचित कचेला

इस उद्देश्य के लिए एंड्रॉइड-जॉब का उपयोग करना वास्तव में बहुत अच्छा समाधान नहीं है। इसका मतलब चीजों को एक बार या समय-समय पर निर्दिष्ट समय पर चलाना है। यह अलार्म और इस तरह के लिए रेट्रो-संगतता समर्थन लाने के लिए है। यह एपीआई क्यों बदल गया, और पढ़ने के पूरे विचार के खिलाफ जाता है: developer.android.com/training/monitoring-device-state/… आप जल्दी से क्यों के लिए एक अर्थ प्राप्त कर सकते हैं।
पेड्रोवेलोसो

केवल समस्या यह है कि एंड्रॉइड एन में इसे केवल भविष्य में न्यूनतम 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अपने AndroidManifest.xml में अनुमति जोड़ना न भूलें :

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

मैं आप से उपयोगी टिप्पणियों और सुधारों को पढ़ने के लिए उत्सुक हूं।


1
मुझे कॉलबैक के लिए कुछ बदलना था ताकि मुख्य थ्रेड पर एक गतिविधि (संदर्भ) में "विचारों को स्पर्श" करने में सक्षम हो: (context as AppCompatActivity).runOnUiThread(object: Runnable{ override fun run() { onConnectionAvailable.invoke() } })इसके बजाय onConnectionAvailable.invoke()। उसी के लिए onConnectionLost.invoke()
Андрей Воробьев

हां, आपके उपयोग के मामले के आधार पर आपको थ्रेड स्विच करने की आवश्यकता हो सकती है। मैं इसे कक्षा का हिस्सा नहीं बनाऊंगा, लेकिन इसके बजाय कक्षा के उपभोक्ता को इस बात का ध्यान रखना चाहिए। लेकिन संकेत के लिए धन्यवाद।
JJD

2

Android N (Nougat) को लक्षित करने वाले ऐप्स को CONNECTIVITY_ACTIONप्रकट में परिभाषित प्रसारण ( Svelte देखें ) प्राप्त नहीं होते हैं ।

संभव समाधान:

  • ConnectivityManager.registernetworkCallback()एप्लिकेशन चलने के बाद स्पष्ट रूप से नेटवर्क कॉलबैक पंजीकृत करें ।
  • के JobSchedulerमाध्यम से एक का उपयोग करें , और एक बिना नेटवर्क वाले नेटवर्क को निर्दिष्ट करें setRequiredNetworkType()

Android O भी देखें - पृष्ठभूमि में कनेक्टिविटी परिवर्तन का पता लगाएं


1

मैं @rds द्वारा सुझाए गए उत्तर से सहमत हूं ।

ध्यान रखें कि CONNECTIVITY_ACTION को एपीआई स्तर 28 में पदावनत किया गया है।

यदि आपके पास आवश्यकता है कि ऐप के मारे जाने के बावजूद Wifi राज्य (कनेक्ट / डिस्कनेक्ट) का पता लगाया जाना चाहिए और आप नवीनतम संस्करण को लक्षित करना चाहते हैं तो आपके पास अधिक विकल्प नहीं हैं।

आपको उपयोग करने की आवश्यकता है connectivityManager.registerNetworkCallback(networkRequest, networkCallback)

सवाल यह है कि आप ब्रॉडकास्टर का उपयोग नहीं कर सकते हैं तो कैसे?

आप या तो JobScheduler का उपयोग कर सकते हैं या बेहतर अगर WorkManager (आवधिक अनुरोध)। समय-समय पर क्यों क्योंकि अगर यह वनटाइमरैपेस्ट है तो यह केवल एक बार ही चल पाएगा और आपके ऐप के अग्रभूमि में होने पर भी सुनता रहेगा।

प्रलेखन कहता है:

कॉलबैक तब तक कॉल किया जाता रहेगा जब तक कि एप्लिकेशन से बाहर नहीं निकल जाता है या #unregisterNetworkCallback (NetworkCallback)} को लिंक नहीं किया जाता है।

एक बार जब ऐप को मार दिया जाता है या हाल की ऐप सूची से हटा दिया जाता है, तो नेटवर्क कॉलबैक नहीं सुन पाएगा।

तो, आपको ऐप को लगातार सुनने के लिए ऐसी आवधिक नौकरियों की आवश्यकता है। अवधि कितनी होनी चाहिए? यह आपके ऊपर है और केस टू केस पर निर्भर करता है।

मुझे पता है कि यह थोड़ा बदसूरत तरीका है लेकिन यह है कि यह कैसा है। एक चुनौती यह हो सकती है कि यदि उपयोगकर्ता का उपकरण डोज़ मोड में है या ऐप स्टैंडबाय स्थिति में है, तो आपकी नौकरी में देरी हो सकती है।


यह भी ध्यान रखें कि कुछ भारी अनुकूलित EMUI पर, MIUI Android OS कार्य प्रबंधक (आवधिक कार्य) को हमेशा सही ढंग से काम करने की आवश्यकता नहीं होती है।
कबाब क्राबी

1

जब हम registerNetworkCallbackविधि का उपयोग करके नेटवर्क कॉलबैक पंजीकृत करते हैं तो कभी-कभी यह ट्रिगर नहीं होता है और कभी-कभी यह गलत-सकारात्मक ट्रिगर करता है:

  1. यदि हम इंटरनेट कनेक्शन के साथ एक ऐप शुरू करते हैं तो onAvailableविधि ट्रिगर हो जाती है।
  2. लेकिन अगर डिवाइस पर कोई इंटरनेट कनेक्शन नहीं है, जब हम एक ऐप शुरू करते हैं तो कुछ भी नहीं NetworkCallbackकहा जाता है (यह पी 1 के कारण बहुत अजीब है)
  3. अगर हमारे पास wifi कनेक्शन है लेकिन बिना इंटरनेट कनेक्शन के 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 
}

1

@ कबाबक्राबी के जवाब पर आधारित:

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"}")
})
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.