不推荐使用ConnectivityManager.CONNECTIVITY_ACTION

时间:2016-04-05 09:12:03

标签: android

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

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

既然它已被弃用,任何人都可以建议我采用另一种方法来获取当前的网络状态吗?

13 个答案:

答案 0 :(得分:70)

将弃用的是后台应用程序接收网络连接状态更改的能力。

正如David Wasser所述,如果应用程序组件已实例化(未销毁)并且您的registered your receiver programmatically具有其上下文,而不是在清单中执行此操作,则仍可以获得有关连接更改的通知。

或者您可以使用NetworkCallback代替。特别是,您需要覆盖onAvailable以了解已连接的状态更改。

让我快速起草一个片段:

public class ThreadLocal {
 private static ThreadLocal<String> myThreadLocal = new ThreadLocal<>();
}

答案 1 :(得分:22)

Android N的文档指出:

  

定位到Android N的应用不会收到CONNECTIVITY_ACTION   广播,即使他们有明确的条目来请求通知   这些事件。在前台运行的应用程序仍然可以监听   如果他们请求通知,则在其主线程上使用CONNECTIVITY_CHANGE   使用BroadcastReceiver。

这意味着如果您的应用在前台运行,您仍然可以注册<!doctype html> <html> <head> <meta charset="UTF-8"> <title>Sports Day Lineup Generator</title> </head> <body> Hello! What page would you like to see?<br><br> <form id="form2" name="form2" method="POST" action="display.php"> <select id="Year"><option value="7">Y7</option><option value="8">Y8</option><option value="9">Y9</option><option value="10">Y10</option><option value="11">Y11</option><option value="12">IB1</option><option value="13">IB2</option></select> <select id="Gender"><option value="0">Girls</option><option value="1">Boys</option></select> <select id="Event"> <option value="1">100m</option><option value="2 relay">100m Relay</option><option value="3">400m</option><option value="4">800m</option><option value="5">Indoor Sports</option><option value="6">High Jump</option><option value="7">Long Jump</option><option value="8">Triple Jump</option><option value="9">Shotput</option> </select><br> <input type="submit" value="generate"> </form> OR <form id="form2" name="form2" method="POST" action="displayAll.php"><input type="submit" value="generate all tables"></form> </body> </html> ,以便检测网络连接的变化。

答案 2 :(得分:12)

我将更新 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

    override fun onActive() {
        super.onActive()
        updateConnection()
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(getConnectivityManagerCallback())
            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() {
        val builder = NetworkRequest.Builder()
            .addTransportType(android.net.NetworkCapabilities.TRANSPORT_CELLULAR)
            .addTransportType(android.net.NetworkCapabilities.TRANSPORT_WIFI)
        connectivityManager.registerNetworkCallback(builder.build(), getConnectivityManagerCallback())
    }

    private fun getConnectivityManagerCallback(): 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("Should not happened")
        }
    }

    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的帮助。

答案 3 :(得分:9)

请首先检查@Amokrane Chentir答案是否支持android N。

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

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

在用户界面中观察(活动/片段):

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

答案 4 :(得分: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();

答案 5 :(得分:5)

基于@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"}")
})

答案 6 :(得分:2)

定位到Android N(牛轧糖)的应用不会收到清单中定义的CONNECTIVITY_ACTION广播(请参阅Svelte)。

可能的解决方案:

另请参阅Android O - Detect connectivity change in background

答案 7 :(得分:1)

我同意@rds建议的answer

请记住,CONNECTIVITY_ACTION在API级别28中已弃用。

  

如果您有以下要求,则无论是否已检测到Wifi状态(连接/断开连接)   应用被杀死,您想定位最新版本,那么您   没有太多选择。

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

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

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

Documentation说:

  

在应用程序退出或链接#unregisterNetworkCallback(NetworkCallback)}被调用之前,回调将继续被调用。

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

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

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

答案 8 :(得分:1)

当我们使用registerNetworkCallback方法注册网络回调时,有时不会触发,有时会触发误报:

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

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

只需总结thisthis的答案(但仅适用于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 
}

答案 9 :(得分:0)

我写了一个基于Sayam's answer但没有LiveData的Kotlin实现。我决定调用(此时)针对Android Nougat的最新API方法(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()

请不要忘记在您的 AndroidManifest.xml 中添加ACCESS_NETWORK_STATE权限:

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

我期待着从您那里获得有益的评论和改进。

答案 10 :(得分:0)

您可以轻松使用库 com.github.vladan29:internet_checker:1.0.3。 使用该库,无需了解反应式编程并考虑删除观察者。只需几行代码即可连续安全地检查互联网连接。

您可以在以下位置找到所有必要的说明:https://github.com/vladan29/internet_checker/blob/master/README.md#internet_checker

答案 11 :(得分:0)

这没什么特别的,我只是将上面的答案转换为 java,因为 java 没有答案。

  public class ConnectivityWatcher extends LiveData<Boolean> {
    private static final String TAG = "ConnectivityWatcher";
    private final ConnectivityManager connectivityManager;
    private ConnectivityManager.NetworkCallback connectivityManagerCallback;
    private final NetworkRequest.Builder networkRequestBuilder;
    @NotNull
    private final Context context;

    protected void onActive() {
        super.onActive();
        this.updateConnection();
        if (Build.VERSION.SDK_INT >= 24) {
            try {
                this.connectivityManager.registerDefaultNetworkCallback(this.getConnectivityMarshmallowManagerCallback());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else if (Build.VERSION.SDK_INT >= 23) {
            try {
                this.marshmallowNetworkAvailableRequest();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else if (Build.VERSION.SDK_INT >= 21) {
            try {
                this.lollipopNetworkAvailableRequest();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    }

    protected void onInactive() {
        super.onInactive();
        Log.e(TAG, "onInactive: I am inActive ");
        if (Build.VERSION.SDK_INT >= 21) {
            connectivityManager.unregisterNetworkCallback(connectivityManagerCallback);
        }

    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void lollipopNetworkAvailableRequest() throws IllegalAccessException {
        this.connectivityManager.registerNetworkCallback(this.networkRequestBuilder.build(), this.getConnectivityLollipopManagerCallback());
    }

    @TargetApi(Build.VERSION_CODES.M)
    private void marshmallowNetworkAvailableRequest() throws IllegalAccessException {
        this.connectivityManager.registerNetworkCallback(this.networkRequestBuilder.build(), this.getConnectivityMarshmallowManagerCallback());
    }

    private ConnectivityManager.NetworkCallback getConnectivityLollipopManagerCallback() throws IllegalAccessException {
        if (Build.VERSION.SDK_INT >= 21) {
            this.connectivityManagerCallback = new ConnectivityManager.NetworkCallback() {
                public void onAvailable(@NotNull Network network) {
                    postValue(true);
                }

                public void onLost(@NotNull Network network) {
                    postValue(false);
                }
            };

            return this.connectivityManagerCallback;
        } else {
            throw new IllegalAccessException();
        }
    }

    private ConnectivityManager.NetworkCallback getConnectivityMarshmallowManagerCallback() throws IllegalAccessException {
        if (Build.VERSION.SDK_INT >= 23) {
            this.connectivityManagerCallback = new ConnectivityManager.NetworkCallback() {
                public void onCapabilitiesChanged(@NotNull Network network, @NotNull NetworkCapabilities networkCapabilities) {
                    if (connectivityManager != null) {
                        NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
                        if (capabilities != null) {
                            if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                                postValue(true);
                            }
                        }
                    }
                }

                public void onLost(@NotNull Network network) {
                    postValue(false);
                }
            };

            return this.connectivityManagerCallback;
        } else {
            throw new IllegalAccessException();
        }
    }

    private void updateConnection() {
        boolean isConnected;
        NetworkInfo activeNetwork = this.connectivityManager.getActiveNetworkInfo();
        if (activeNetwork != null) {
            isConnected = activeNetwork.isConnected();
        } else {
            isConnected = false;
        }
        this.postValue(isConnected);
    }

    @NotNull
    public final Context getContext() {
        return this.context;
    }

    public ConnectivityWatcher(@NotNull Context context) {
        this.context = context;
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm == null) {
            throw new NullPointerException("null cannot be cast to non-null type android.net.ConnectivityManager");
        } else {
            this.connectivityManager = cm;
            this.networkRequestBuilder = (new NetworkRequest.Builder()).addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addTransportType(NetworkCapabilities.TRANSPORT_WIFI).addTransportType(NetworkCapabilities.TRANSPORT_VPN);
        }
    }
}

答案 12 :(得分:0)

我决定检查解决方案 here,并进行了一些改进和示例:

ConnectionLiveData.kt

class ConnectionLiveData(private val context: Context) : LiveData<Boolean>() {
    private val connectivityManager: ConnectivityManager = context.getSystemService()!!
    private lateinit var networkReceiver: BroadcastReceiver
    private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback

    @UiThread
    override fun setValue(value: Boolean?) {
        if (getValue() == value)
            return
        super.setValue(value)
    }

    @UiThread
    override fun onActive() {
        super.onActive()
        updateConnection()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
                @WorkerThread
                override fun onCapabilitiesChanged(network: Network,
                    networkCapabilities: NetworkCapabilities) {
                    super.onCapabilitiesChanged(network, networkCapabilities)
                    if (networkCapabilities.hasCapability(
                            NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        && networkCapabilities.hasCapability(
                            NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                        postValue(true)
                    }
                }

                @WorkerThread
                override fun onLost(network: Network) {
                    postValue(false)
                }
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                connectivityManager.registerDefaultNetworkCallback(connectivityManagerCallback)
            } else {
                val networkRequest = NetworkRequest.Builder()
                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build()
                connectivityManager.registerNetworkCallback(networkRequest,
                    connectivityManagerCallback)
            }
        } else {
            networkReceiver = object : BroadcastReceiver() {
                @UiThread
                override fun onReceive(context: Context, intent: Intent) {
                    updateConnection()
                }
            }
            @Suppress("DEPRECATION")
            context.registerReceiver(networkReceiver,
                IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
        }
    }

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

    @UiThread
    @Suppress("DEPRECATION")
    private fun updateConnection() {
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        value = activeNetwork?.isConnected == true
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val textView = findViewById<TextView>(R.id.textView)
        ConnectionLiveData(this).observe(this, {
            textView.text = if (it) "connected" else "disconnected"
            Log.d("AppLog", "connected?$it")
        })
        val internetSettings = findViewById<View>(R.id.internetSettings)
        internetSettings.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
        internetSettings.setOnClickListener {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                startActivity(Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY))
        }
        findViewById<View>(R.id.wifiSettings).setOnClickListener {
            startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
        }
        findViewById<View>(R.id.mobileDataSettings).setOnClickListener {
            startActivity(Intent(Settings.ACTION_DATA_ROAMING_SETTINGS))
        }
    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"
    android:orientation="vertical" tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" />

    <Button
        android:id="@+id/internetSettings" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="internet settings" />

    <Button
        android:id="@+id/wifiSettings" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="wifi settings" />

    <Button
        android:id="@+id/mobileDataSettings" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="mobile-data settings" />
</LinearLayout>

清单要求:

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