不推荐使用ConnectivityManager.CONNECTIVITY_ACTION


94

在Android N中,官方网站上提到“针对Android N的应用不会收到CONNECTIVITY_ACTION广播”。并且还提到JobScheduler可以用作替代方法。但是JobScheduler不能提供与CONNECTIVITY_ACTION广播完全相同的行为。

在我的Android应用程序中,我正在使用此广播来了解设备的网络状态。我想知道这种状态是广播状态CONNECTING还是CONNECTEDCONNECTIVITY_ACTION广播的帮助下,它最适合我的要求。

现在已经过时了,有人可以建议我获取当前网络状态的另一种方法吗?


10
而且,如果某天OP希望某些行为需要targetSdkVersion将N 提升到N或更高,该怎么办?
迈克尔

1
好吧,我也知道,如果我不将我的应用程序定位到Android NI,它将收到广播。但是我的应用程序需要支持AndroidN。如何在Android N中获得相同的广播行为?我可以尝试其他方法吗?@DavidWasser
Raghuram db

有时候,我认为担心未来会更有意义。这纯粹是一种实用的编程方法。当然,您始终可以尝试确保您的代码不使用任何不推荐使用的功能。另一方面,不推荐使用的功能通常会保留很长一段时间,并且可能在不推荐使用的功能消失之前,您的应用将被淘汰。Android N非常新,以至于我不会花很多时间担心它。然而。只是我的2美分。请注意,我对此问题发表了评论,但并不表示“不要那样做”是有效的答案。
David Wasser

2
@Raghuramdb您的应用程序可以在Android n。可运行,即使您没有定位你的应用程序到Android N.你只需要指定Android n如果要使用仅适用于Android的N.功能
大卫·瓦瑟

2
即使在定位API29时,您仍然可以BroadcastReceiverandroid.net.conn.CONNECTIVITY_CHANGEintent过滤器与一起使用,只需在中注册它即可Application.OnCreate。关闭应用程序后,您将不会获得任何更新。
Pierre

Answers:


97

不推荐使用后台应用程序接收网络连接状态更改的功能。

正如David Wasser所说,如果实例化(未销毁)应用程序组件,并且已通过编程方式将接收者与其上下文进行了注册,而不是在清单中进行操作,则仍会收到有关连接更改的通知。

或者,您可以改用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.net.conn.CONNECTIVITY_CHANGE” />中的manifest.xml不再拥有的Android N.任何影响
卓晏城

2
@CheokYanCheng AFAIK是正确的。您需要有一个在前台运行的进程来侦听连接事件。似乎由Android框架工程师做出的假设是,大多数情况下都是监听连接事件,以便知道何时开始在客户端和服务器之间同步数据。因此,JobScheduler是该用例的推荐方法。
Amokrane Chentir

25
大声笑什么,另外10个android更新,我们所能编写的只是一个hello world应用程序
DennisVA,

1
我是否需要注销NetworkCallback(例如,在活动的onDestroy方法中)?
Ruslan Berozov

2
@Ruslan当然可以,否则您将泄漏已注册的内容
DennisVA '19

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

顺便说一句,感谢sayem为您提供的解决方案。


2
惊人的解决方案!

2
使用实时数据并支持旧版本的很好解决方案
Prakash Shukla

这是互联网上可用的最佳解决方案。
卡兰·沙尔玛

很好的解决方案!但是有一个“ not”(不)-使用onAvailable(network:Network?)方法是错误的方法,因为它甚至无法调用Internet。最好使用onCapabilitiesChanged(network:Network,networkCapabilities:NetworkCapabilities)并检查networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)和networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)。
DmitryKanunnikoff

如何在此代码库中获取IP和网络类型?
A_rmas

28

Android N的文档指出:

定位到Android N的应用程序即使收到清单项来请求这些事件的通知,也不会收到CONNECTIVITY_ACTION广播。如果前台运行的应用程序请求使用BroadcastReceiver进行通知,则它们仍可以在其主线程上侦听CONNECTIVITY_CHANGE。

这意味着BroadcastReceiver如果您的应用程序在前台运行,您仍然可以注册一个,以检测网络连接的变化。



这是否意味着该应用程序不在前台时将停止接收广播?(例如,我不能在服务中收听它?)
sundie

1
我不确定,我需要对其进行测试以确保。但是,阅读文档可能会发现,如果您的应用程序不在前台,那么您将不会得到广播Intent
David Wasser

2
但是,对于任何sip应用程序(VoIP)来说,检测后台的连接变化都是必不可少的……这些应用程序通常在后台运行数天,并且仅在有电话打入时才跳到前台(就像电话的拨号器一样)。这些应用需要在后台自动重新连接。这会从android平台中杀死所有这些应用程序(没有自己的推送服务器),因为它们将处于离线状态。总是。
Grisgram '17

只需使用Firebase推送服务即可。
Pierre

21

请首先检查@Amokrane Chentir答案以获取android N支持。

对于那些想要在所有api级别上支持并在ui中进行观察的人,请检查以下代码。

NetworkConnection的LiveData:

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

顺便说一句,您不需要IntentFilter显式定义。像这样:var intentFilter = IntentFilter(CONNECTIVITY_ACTION)
Ryan Amaral

感谢您的建议。我不想每次都在onActive中创建对象。
Sayem

我的意思是您不需要显式定义其类型(和)的2个全局变量/属性(intentFilter和)。connectivityManagerIntentFilterConnectivityManager
瑞安·阿玛拉尔

7

几天前,我遇到了同样的问题,因此决定使用这个库Android-Job

该库使用 JobSchedularGcmNetworkManagerBroadcastReceiver取决于运行该应用程序的Android版本。

找工作很容易

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

1
我已经尝试过相同的调度程序,并得到像这样的异常您正在尝试建立没有限制的工作,这是不允许的。您能帮我们解决这个问题吗?
Sanket Kachhela'1

为此目的使用Android-Job确实不是一个很好的解决方案。它的意思是在指定的时间运行一次或一次。旨在为“警报”等提供追溯兼容性。这与API为何更改的整个想法背道而驰,请阅读: developer.android.com/training/monitoring-device-state/… 您可以快速了解其原因。
pedronveloso

唯一的问题是,在Android N中,将来只能安排至少15分钟的时间
Fire Crow,

4

我写了一个Kotlin实现,它基于Sayam的答案,但是没有LiveData。我决定调用(此时)ConnectivityManager#registerDefaultNetworkCallback针对Android Nougat的最新API方法()。

/**
 * 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


1

我同意了答案由@rds建议。

请记住,API级别28不推荐使用CONNECTIVITY_ACTION

如果您有一个要求,尽管应用被终止,但仍应检测到Wifi状态(连接/断开连接),并且您希望定位到最新版本,那么您没有太多选择。

您需要使用 connectivityManager.registerNetworkCallback(networkRequest, networkCallback)

问题是您不能使用BroadcastReceiver,那怎么办?

您可以使用JobScheduler,也可以使用WorkManager(定期请求)更好的服务。为什么选择“周期性”,因为如果它是一个OneTimeRequest,那么它将只能运行一次并在您的应用程序处于前台时继续监听。

文档说:

回调将继续被调用,直到应用程序退出或链接#unregisterNetworkCallback(NetworkCallback)}被调用为止。

一旦应用被杀死或从最近的应用列表中删除,networkCallback将无法收听。

因此,您需要进行此类定期工作以使应用程序不断进行监听。持续时间应该是多少?这取决于您,取决于具体情况。

我知道这有点丑陋,但这就是事实。一个挑战可能是,如果用户的设备处于打ze模式或应用程序处于待机状态,则您的工作可能会延迟。


还请记住,在一些高度自定义的EMUI上,MIUI Android OS workManager(定期任务)不必始终正常运行。
Kebab Krabby

1

当我们使用registerNetworkCallback方法注册网络回调时,有时它不会触发,有时它会触发假阳性:

  1. 如果我们通过互联网连接启动应用, onAvailable方法将触发。
  2. 但是,如果启动应用程序时设备上没有互联网连接,则不会NetworkCallback调用任何内容(由于第1页,这很奇怪)
  3. 如果我们有wifi连接但没有互联网连接,则onAvailable方法触发。我认为这是假阳性行为,因为我们希望观察到互联网连接。

如您在下面的代码中看到的,默认情况下,Internet连接可用,并且只有在更改时才会触发。没有假阳性触发器。

只需总结一下这个答案即可(但仅适用于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

基于@KebabKrabby的答案:

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"}")
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.