不推荐使用 ConnectivityManager.CONNECTIVITY_ACTION

在 Android N 中,官方网站提到“针对 Android N 的应用程序不接收 CONNECTIVITY _ ACTION 广播”。同时也提到了 JobScheduler可以作为一种替代品。但是 JobScheduler并不提供与 CONNECTIVITY_ACTION广播完全相同的行为。

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

既然它已经被废弃了,有人能给我提供一种获得当前网络状态的替代方法吗?

60512 次浏览

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

正如 David Wasser所说,如果应用程序组件被实例化(没有被销毁) ,并且 以编程方式注册接收器带有其上下文,而不是在清单中执行,那么您仍然可以得到连接更改的通知。

或者您可以使用 网络回拨代替。特别是,您需要重写 可用以进行连接状态更改。

让我快速地起草一个片段:

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

Android N 的文档如下:

针对 Android N 的应用程序不接收 CONNECTIVITY _ ACTION 广播,即使它们有清单项来请求通知 运行在前台的应用程序仍然可以监听 如果它们请求通知,则在其主线程上执行 CONNECTIVITY _ CHOGE 广播接收器。

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

几天前我遇到了同样的问题,我决定使用这个库 机器人-工作

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

开始一项工作是相当容易的

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

Apps targeting Android N (Nougat) do not receive CONNECTIVITY_ACTION broadcasts defined in the manifest (see Svelte).

可能的解决办法:

See also Android O-检测后台连接变化

请首先查看@Amokrane Chentir 对 android N 支持的回答。

对于那些想要支持所有 api 级别和观察它在 UI,请检查下面的代码。

网络连接的 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
})

我会更新 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)
}
}

And same usage:

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

顺便说一句,谢谢你的解决方案。

我同意@rds 建议的 answer

请记住,在 API 级别28中不推荐使用 连通性 _ 行动

如果您需要检测 Wifi 状态(连接/断开连接) ,尽管 应用程序被关闭,你想目标的最新版本,然后你 别无选择。

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

问题是,你不能使用 BroadcastReceiver,那么如何呢?

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

文件说:

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

一旦应用程序被关闭或从最近的应用程序列表中删除,networkCallback 将无法监听。

因此,你需要这样的定期工作,使应用程序不断地监听。持续时间应该是多少?这取决于你,取决于每个案子。

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

我编写了一个 Kotlin 实现,它基于 Sayam 的回答,但没有 LiveData。我决定调用(此时此刻)针对 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" />

我期待着阅读你的有益的意见和改进。

当我们使用 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
}

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

您可以很容易地使用库 com.github.vladan29: internet _ check: 1.0.3。 有了这个图书馆就不需要知道响应式编程,也不需要考虑移除观察者。只有几行代码将提供连续和安全的互联网连接检查。

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

没什么特别的,我只是把上面的答案转换成了 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);
}
}
}

I've decided to check on the solution 给你, and made some improvements and sample. I also made it avoid multiple setting of the same value so it won't cause the observer to keep getting the same value, one after another :

ConnectionLiveData.kt

class ConnectionLiveData(private val context: Context) : LiveData<Boolean>() {
private val handler = Handler(Looper.getMainLooper())
private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback
private lateinit var networkReceiver: BroadcastReceiver


init {
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
@AnyThread
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
setNewValue(true)
}
}


override fun onAvailable(network: Network) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1)
setNewValue(true)
}


override fun onLost(network: Network) {
setNewValue(false)
}
}
}
else -> {
networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
updateConnection()
}
}
}
}
}


/**this prevents observers to get multiple times the same value*/
@AnyThread
private fun setNewValue(isConnected: Boolean) {
handler.removeCallbacksAndMessages(null)
if (isUiThread()) {
if (value != isConnected)
@SuppressLint("WrongThread")
value = isConnected
return
}
handler.post {
if (value != isConnected)
value = isConnected
}
}


@UiThread
override fun onActive() {
super.onActive()
val connectivityManager: ConnectivityManager = context.getSystemService()!!
updateConnection()
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> connectivityManager.registerDefaultNetworkCallback(connectivityManagerCallback, handler)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(connectivityManagerCallback)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
val networkRequest =
NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build()
connectivityManager.registerNetworkCallback(networkRequest, connectivityManagerCallback)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
val networkRequest =
NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build()
connectivityManager.registerNetworkCallback(networkRequest, connectivityManagerCallback)
}
else -> {
@Suppress("DEPRECATION") context.registerReceiver(networkReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
}
}
}


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




@Suppress("DEPRECATION")
private fun updateConnection() {
setNewValue(isConnectedToInternet(context))
}


companion object {
@JvmStatic
fun isUiThread(): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) Looper.getMainLooper().isCurrentThread else Thread.currentThread() === Looper.getMainLooper().thread


private fun isConnectedToInternet(context: Context): Boolean {
val connectivityManager: ConnectivityManager = context.getSystemService()!!
val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
return activeNetwork?.isConnectedOrConnecting == 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" />

请注意,它有一个罕见的问题时,飞机模式被打开,暂时它认为有没有连接,然后相反,然后再回来,有没有连接。关于这个 这里的报道。

这是我的 Java 解决方案,从 Android Lollipop 到 android s 及以上版本

@RequiresApi (api = Build.VERSION_CODES.LOLLIPOP)
public final class NetworkWatcher extends LiveData<Boolean> {
//    Variables
private final Context context;


private final ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback networkCallback;


private NetworkRequest networkRequest;


private NetworkWatcher.NetworkStateWatcherReceiver networkStateWatcherReceiver;




//    Constructors
public NetworkWatcher(@NonNull Context context){
this.context = context;


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
this.connectivityManager = context.getSystemService(ConnectivityManager.class);


this.networkCallback = new ConnectivityManager.NetworkCallback(){
@Override
public void onLost(@NonNull Network network) {
NetworkWatcher.super.postValue(false);
}


@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
NetworkWatcher.super.postValue(
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
);
}
};
this.networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build();
} else {
this.networkStateWatcherReceiver = new NetworkStateWatcherReceiver();
this.networkStateWatcherReceiver.setOnNetworkChangedListener(NetworkWatcher.super::postValue);
}
}




//    Override methods
@Override
protected void onActive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
this.connectivityManager.registerBestMatchingNetworkCallback(this.networkRequest, this.networkCallback, null);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
this.connectivityManager.registerDefaultNetworkCallback(this.networkCallback);
} else {
this.connectivityManager.registerNetworkCallback(this.networkRequest, this.networkCallback);
}
} else {
this.context.registerReceiver(
this.networkStateWatcherReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
);
}
}


@Override
protected void onInactive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
this.connectivityManager.unregisterNetworkCallback(this.networkCallback);
} else {
this.context.unregisterReceiver(this.networkStateWatcherReceiver);
}
}






//    Inner method classes
@TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
private static final class NetworkStateWatcherReceiver extends BroadcastReceiver {
//        Variables
private NetworkStateWatcherReceiver.OnNetworkChangedListener onNetworkChangedListener;




//        Constructors
public NetworkStateWatcherReceiver() {
}




//        Override methods
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
if (this.onNetworkChangedListener != null) {
boolean isConnected = this.isConnected(context);
this.onNetworkChangedListener.onNetworkChangedListener(isConnected);
}
}




//        Methods
private boolean isConnected(@NonNull Context context){
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();


return networkInfo != null && networkInfo.isConnected();
}
public void setOnNetworkChangedListener(@Nullable OnNetworkChangedListener onNetworkChangedListener) {
this.onNetworkChangedListener = onNetworkChangedListener;
}






//        Inner interfaces
private interface OnNetworkChangedListener{
void onNetworkChangedListener(boolean isConnected);
}
}
}

在 onCreate 方法的主活动中使用它

new NetworkWatcher(this).observe(this, aBoolean -> {
if (aBoolean){
// Internet connection available
} else {
// No internet connection
}
});

虽然重写 onAvailable(Network network)有时确实有效,但是当调用 oniliable ()时,新的网络可能还没有完全运行。根据这个文档 https://developer.android.com/reference/android/net/ConnectivityManager.OnNetworkActiveListener,我最终使用了以下内容

connectivityManager.addDefaultNetworkActiveListener()