Android 监听网络状态变化(无切换中间态版)

需求:

  • 获取当前的网络状态与类型(WIFI、数据流量)
  • 监听网络状态真正变化
  • 监听网络类型发生变化

业务场景:

  • 用户打开 App 时、使用过程中,出现无网络时,显示 Toast 提示。但当 wifi、数据流量 互相切换的过程中不要有提示。
  • 下载功能支持检测到用户连接上 wifi 时开启静默下载,当换成 数据流量 时停止静默下载。

需求分析:

获取当前网络状态与类型

即提供两个方法,用于获取当前的网络状态、网络类型。

监听网络状态真正变化

网络状态真正变化,首先明确网络状态只有【有网】与【无网】,所以当 WIFI 和 数据流量 同时开启的情况下,仅关闭一项,不会提示网络状态的变更。

监听网络类型发生变化

网络类型发生变化,是指当前使用的网络类型发生变化。举个例子,WIFI、数据流量同时开启,理论上当前网络类型是 WIFI,所以当仅关闭 数据流量 时,不会提示网络类型变更,但仅关闭 WIFI 时,会提示网络类型变更为 数据流量。

这里还需要注意一点,有一个"系统默认网络"的概念:系统通常首选不按流量计费的网络而非按流量计费的网络,首选网速较快的网络而非网速较慢的网络。

技术实现:

常见监听网络状态有三种方式:

  • 监听广播
  • ConnectivityManager#registerDefaultNetworkCallback()
  • ConnectivityManager#registerNetworkCallback()

下面逐一实现看效果:

监听网络状态变化广播

kotlin 复制代码
class NetConnectReceiver: BroadcastReceiver() {
  override fun onReceive(context: Context?, intent: Intent?) {
    Log.e("qingshan", "网络状态改变")
    context?.getSystemService(ConnectivityManager::class.java)?.allNetworkInfo?.filter {
      it.typeName == "MOBILE" || it.typeName == "WIFI"
    }?.forEach {networkInfo ->
      Log.e("qingshan", "${networkInfo?.typeName}, isConnect= ${networkInfo?.isConnected}")
    }
  }
}

//动态注册广播监听
class CustomApplication: Application() {
  override fun onCreate() {
    super.onCreate()
    //这里模拟工具类场景:全局一个监听,然后在工具类中分发。
    registerReceiver(NetConnectReceiver(), IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
  }
}

效果:

  • 数据流量、wifi 全关,冷启动。收到两次广播,均表示【数据流量、wifi 】无连接。
kotlin 复制代码
2023-11-10 14:21:58.081 13917-13917 qingshan    E  网络状态改变
2023-11-10 14:21:58.082 13917-13917 qingshan    E  MOBILE, isConnect= false
2023-11-10 14:21:58.082 13917-13917 qingshan    E  WIFI, isConnect= false

2023-11-10 14:21:58.083 13917-13917 qingshan    E  网络状态改变
2023-11-10 14:21:58.083 13917-13917 qingshan    E  MOBILE, isConnect= false
2023-11-10 14:21:58.083 13917-13917 qingshan    E  WIFI, isConnect= false
  • 数据流量、wifi 全开,冷启动。收到连续两次广播,均表示当前【WIFI】连接。
kotlin 复制代码
2023-11-10 14:13:46.002 13917-13917 qingshan    E  网络状态改变
2023-11-10 14:13:46.002 13917-13917 qingshan    E  MOBILE, isConnect= false
2023-11-10 14:13:46.002 13917-13917 qingshan    E  WIFI, isConnect= true

2023-11-10 14:13:46.003 13917-13917 qingshan    E  网络状态改变
2023-11-10 14:13:46.003 13917-13917 qingshan    E  MOBILE, isConnect= false
2023-11-10 14:13:46.003 13917-13917 qingshan    E  WIFI, isConnect= true
  • 数据流量、wifi 全开,仅关闭流量。无广播。
  • 数据流量、wifi 全开,仅关闭wifi(用于模拟断开wifi 或 wifi网络不佳时系统自动启用数据流量)。收到多次广播,有时表示先【数据流量、wifi 】无连接,然后又出现【数据流量】连接,有时均表示当前【数据流量】连接。
kotlin 复制代码
2023-11-10 14:18:46.622 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:18:46.624 13917-13917 qingshan   E  MOBILE, isConnect= true
2023-11-10 14:18:46.624 13917-13917 qingshan   E  WIFI, isConnect= false

2023-11-10 14:18:46.624 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:18:46.624 13917-13917 qingshan   E  MOBILE, isConnect= true
2023-11-10 14:18:46.624 13917-13917 qingshan   E  WIFI, isConnect= false

2023-11-10 14:18:46.665 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:18:46.666 13917-13917 qingshan   E  MOBILE, isConnect= true
2023-11-10 14:18:46.666 13917-13917 qingshan   E  WIFI, isConnect= false

2023-11-10 14:18:46.666 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:18:46.666 13917-13917 qingshan   E  MOBILE, isConnect= true
2023-11-10 14:18:46.666 13917-13917 qingshan   E  WIFI, isConnect= false

有时日志如下:

kotlin 复制代码
2023-11-10 14:25:03.460 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:25:03.461 13917-13917 qingshan   E  MOBILE, isConnect= false
2023-11-10 14:25:03.461 13917-13917 qingshan   E  WIFI, isConnect= false

2023-11-10 14:25:03.461 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:25:03.462 13917-13917 qingshan   E  MOBILE, isConnect= false
2023-11-10 14:25:03.462 13917-13917 qingshan   E  WIFI, isConnect= false

2023-11-10 14:25:03.527 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:25:03.528 13917-13917 qingshan   E  MOBILE, isConnect= true
2023-11-10 14:25:03.528 13917-13917 qingshan   E  WIFI, isConnect= false

2023-11-10 14:25:03.528 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:25:03.528 13917-13917 qingshan   E  MOBILE, isConnect= true
2023-11-10 14:25:03.528 13917-13917 qingshan   E  WIFI, isConnect= false
  • 数据流量、wifi 全关。收到两次广播,均表示【数据流量、wifi 】无连接。

注意:先关 wifi 再关数据时,先打印上面("数据流量、wifi 全开,仅关闭wifi"场景)日志,再打印下面日志。

kotlin 复制代码
2023-11-10 14:21:58.081 13917-13917 qingshan    E  网络状态改变
2023-11-10 14:21:58.082 13917-13917 qingshan    E  MOBILE, isConnect= false
2023-11-10 14:21:58.082 13917-13917 qingshan    E  WIFI, isConnect= false

2023-11-10 14:21:58.083 13917-13917 qingshan    E  网络状态改变
2023-11-10 14:21:58.083 13917-13917 qingshan    E  MOBILE, isConnect= false
2023-11-10 14:21:58.083 13917-13917 qingshan    E  WIFI, isConnect= false
  • 仅开数据流量,再开 wifi(用于模拟使用过程中自动连接上wifi)。收到多次广播,均表示【wifi】连接。
kotlin 复制代码
2023-11-10 14:31:21.285 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:31:21.286 13917-13917 qingshan   E  MOBILE, isConnect= false
2023-11-10 14:31:21.286 13917-13917 qingshan   E  WIFI, isConnect= true

2023-11-10 14:31:21.287 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:31:21.287 13917-13917 qingshan   E  MOBILE, isConnect= false
2023-11-10 14:31:21.287 13917-13917 qingshan   E  WIFI, isConnect= true

2023-11-10 14:31:21.317 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:31:21.319 13917-13917 qingshan   E  MOBILE, isConnect= false
2023-11-10 14:31:21.319 13917-13917 qingshan   E  WIFI, isConnect= true

2023-11-10 14:31:21.319 13917-13917 qingshan   E  网络状态改变
2023-11-10 14:31:21.320 13917-13917 qingshan   E  MOBILE, isConnect= false
2023-11-10 14:31:21.320 13917-13917 qingshan   E  WIFI, isConnect= true

ConnectivityManager#registerDefaultNetworkCallback()

要求 android sdk >=24 用于监听"系统默认网络"发生变更。 请勿在回调中调用 ConnectivityManager 的同步方法来查找新可用网络的属性,因为这会受到竞态条件的影响。例如:在 onLost() 回调中调用 connectivityManager.getNetworkCapabilities()。

kotlin 复制代码
class CustomApplication: Application() {
  override fun onCreate() {
    super.onCreate()
    //这里模拟工具类场景:全局一个监听,然后在工具类中分发。
    getSystemService(ConnectivityManager::class.java).apply {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        registerDefaultNetworkCallback(object : NetworkCallback() {

          override fun onAvailable(network: Network) {
            super.onAvailable(network)
            Log.e("qingshan", "def -> onAvailable")
          }

          override fun onLost(network: Network) {
            super.onLost(network)
            Log.e("qingshan", "def -> onLost")
          }

          override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
          ) {
            super.onCapabilitiesChanged(network, networkCapabilities)
            Log.e("qingshan", "def -> 可正常访问网络 = ${networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)} " +
                "& 数据连接 = ${networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)} " +
                "& wifi连接= ${networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)}")
          }
        })
      }    
    }
  }
}

效果

  • 数据流量、wifi 全关,冷启动。无回调触发。
  • 数据流量、wifi 全开,冷启动。触发 onAvailable() 和 onCapabilitiesChanged() 回调。表示当前【WIFI】连接。
kotlin 复制代码
2023-11-10 15:22:31.427  8342-12273 qingshan   E  def -> onAvailable
2023-11-10 15:22:31.427  8342-12273 qingshan   E  def -> 可正常访问网络 = true & 数据连接 = false & wifi连接= true
  • 数据流量、wifi 全开,仅关闭流量。无回调触发。
  • 数据流量、wifi 全开,仅关闭wifi(用于模拟断开wifi 或 wifi网络不佳时系统自动启用数据流量)。触发一次 onLost() 和 onAvailable() 回调,触发多次 onCapabilitiesChanged() 回调。表示当前【数据流量】连接。
kotlin 复制代码
2023-11-10 15:30:26.103  8342-12273 qingshan   E  def -> onLost
2023-11-10 15:30:26.150  8342-12273 qingshan   E  def -> onAvailable
2023-11-10 15:30:26.151  8342-12273 qingshan   E  def -> 可正常访问网络 = true & 数据连接 = true & wifi连接= false
  • 数据流量、wifi 全关。数据流量和 wifi 谁先关闭触发的回调不同,wifi 先关会触发两次 onLost() 回调。有时表示【数据流量、wifi】无连接,有时先表示【wifi】无连接,切换为【数据流量】连接,再表示【数据流量、wifi】无连接。

注意:先关 wifi 再关数据时,先打印上面("数据流量、wifi 全开,仅关闭wifi"场景)日志,再打印下面日志。

kotlin 复制代码
2023-11-10 15:35:42.923  8342-12273 qingshan   E  def -> onLost
  • 仅开数据流量,再开 wifi(用于模拟使用过程中自动连接上wifi)。触发一次 onAvailable() 回调,触发多次 onCapabilitiesChanged() 回调。表示当前【wifi】连接,但有时会有不同的网络状态。
kotlin 复制代码
2023-11-10 15:33:05.596  8342-12273 qingshan   E  def -> onAvailable
2023-11-10 15:33:05.596  8342-12273 qingshan   E  def -> 可正常访问网络 = true & 数据连接 = false & wifi连接= true

有时日志如下:

kotlin 复制代码
2023-11-10 15:39:22.644  8342-12273 qingshan   E  def -> onAvailable
2023-11-10 15:39:22.645  8342-12273 qingshan   E  def -> 可正常访问网络 = false & 数据连接 = true & wifi连接= false
2023-11-10 15:39:22.842  8342-12273 qingshan   E  def -> 可正常访问网络 = true & 数据连接 = true & wifi连接= false

ConnectivityManager#registerNetworkCallback()

用于监听所有网络发生变更。 请勿在回调中调用 ConnectivityManager 的同步方法来查找新可用网络的属性,因为这会受到竞态条件的影响。例如:在 onLost() 回调中调用 connectivityManager.getNetworkCapabilities()。

kotlin 复制代码
class CustomApplication: Application() {
  override fun onCreate() {
    super.onCreate()
    //这里模拟工具类场景:全局一个监听,然后在工具类中分发。
    getSystemService(ConnectivityManager::class.java).apply {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        registerNetworkCallback(NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
            .build(), object : NetworkCallback(){
              override fun onAvailable(network: Network) {
                super.onAvailable(network)
                Log.e("qingshan", "all -> onAvailable")
              }

              override fun onLost(network: Network) {
                super.onLost(network)
                Log.e("qingshan", "all -> onLost")
              }

              override fun onCapabilitiesChanged(
                network: Network,
                networkCapabilities: NetworkCapabilities
              ) {
                super.onCapabilitiesChanged(network, networkCapabilities)
                Log.e("qingshan", "all -> 可正常访问网络 = ${networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)} " +
                    "& 数据连接 = ${networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)} " +
                    "& wifi连接= ${networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)}")
              }
          })
      }    
    }
  }
}

效果

  • 数据流量、wifi 全关,冷启动。无回调触发。
  • 数据流量、wifi 全开,冷启动。触发两次 onAvailable() 和 onCapabilitiesChanged() 回调,表示当前【数据流量、wifi】均连接。
kotlin 复制代码
2023-11-10 17:24:37.153 10713-6397  qingshan   E  all -> onAvailable
2023-11-10 17:24:37.153 10713-6397  qingshan   E  all -> 可正常访问网络 = true & 数据连接 = false & wifi连接= true

2023-11-10 17:24:37.155 10713-6397  qingshan   E  all -> onAvailable
2023-11-10 17:24:37.155 10713-6397  qingshan   E  all -> 可正常访问网络 = true & 数据连接 = true & wifi连接= false
  • 数据流量、wifi 全开,仅关闭流量。触发一次 onLost() 回调,表示当前有网络关闭,具体是什么不知道。
kotlin 复制代码
2023-11-10 17:26:28.243 10713-6397  qingshan   E  all -> onLost
  • 数据流量、wifi 全开,仅关闭wifi(用于模拟断开wifi 或 wifi网络不佳时系统自动启用数据流量)。触发一次 onLoast() 回调,表示当前有网络关闭。因为关闭的是"系统默认网络",所以会触发多次 onCapabilitiesChanged() 回调,表示当前变成【数据流量】连接。
kotlin 复制代码
2023-11-10 17:30:43.302 10713-6397  qingshan   E  all -> onLost
2023-11-10 17:30:45.464 10713-6397  qingshan   E  all -> 可正常访问网络 = true & 数据连接 = true & wifi连接= false
  • 数据流量、wifi 全关。触发两次 onLost() 回调,但先 wifi 时会在两次 onLost() 中间触发一次 onCapabilitiesChanged() 回调。表示当前网络逐个不可用。

先关wifi,再关数据流量,日志如下:

kotlin 复制代码
2023-11-10 17:36:19.335 10713-6397  qingshan   E  all -> onLost
2023-11-10 17:36:19.475 10713-6397  qingshan   E  all -> 可正常访问网络 = true & 数据连接 = true & wifi连接= false
2023-11-10 17:36:20.802 10713-6397  qingshan   E  all -> onLost

先关数据流量,再关wifi,日志如下:

kotlin 复制代码
2023-11-10 17:37:20.487 10713-6397  qingshan   E  all -> onLost
2023-11-10 17:37:22.176 10713-6397  qingshan   E  all -> onLost
  • 仅开数据流量,再开 wifi(用于模拟使用过程中自动连接上wifi)。会触发一次 onAvailable(),触发多次 onCapabilitiesChanged() 回调。表示当前【wifi】已连接(但不意味着正在使用的是 wifi,具体正在使用的网络类型由系统决定,即系统默认网络)。
kotlin 复制代码
2023-11-10 17:33:42.284 10713-6397  qingshan    E  all -> onAvailable
2023-11-10 17:33:42.284 10713-6397  qingshan    E  all -> 可正常访问网络 = true & 数据连接 = false & wifi连接= true
  • 仅开wifi,再开数据流量。会触发一次 onAvailable(),触发多次 onCapabilitiesChanged() 回调。表示当前【数据流量】已连接(但不意味着正在使用的是数据流量,具体正在使用的网络类型由系统决定,即系统默认网络)。
kotlin 复制代码
2023-11-10 17:27:49.875 10713-6397  qingshan   E  all -> onAvailable
2023-11-10 17:27:49.876 10713-6397  qingshan   E  all -> 可正常访问网络 = true & 数据连接 = true & wifi连接= false
2023-11-10 17:27:49.878 10713-6397  qingshan   E  all -> 可正常访问网络 = true & 数据连接 = true & wifi连接= false

总结

根据上面的实际运行效果可以得知:

  • ConnectivityManager#registerNetworkCallback() 是监听所有网络变换的,监听范围广,但无法得知当前"系统默认网络"是什么,可以实现判断网络状态,但无法判断网络类型。
  • 广播监听 与 ConnectivityManager#registerDefaultNetworkCallback() 都是监听"系统默认网络",所以可以实现网络状态与类型的判断,但都存在重复回调的情况,所以要做过滤处理,以及"系统默认网络"切换到普通网络时会有偶现短暂"无网络"状态,需要做延迟处理。
  • 广播监听所使用的方式有标记为"废弃",同时 ConnectivityManager#registerDefaultNetworkCallback() 也有版本的限制,所以可以两者结合使用,优先使用 egisterDefaultNetworkCallback(),广播监听用于兜底。

所以,综合上述,得出如下工具类实现:

kotlin 复制代码
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Handler
import android.os.Looper

sealed class ConnectType(val value: Int) {
  object Mobile : ConnectType(0)
  object Wifi : ConnectType(1)
  object None : ConnectType(-1)

  companion object {
    fun convert2Type(value: Int): ConnectType {
      return when (value) {
        Mobile.value -> Mobile
        Wifi.value -> Wifi
        else -> None
      }
    }
  }
}

object NetConnectManager {

  private var mConnectivityManager: ConnectivityManager? = null
  private val mainHandler = Handler(Looper.getMainLooper())
  private val mNetTypeListener = mutableListOf<(type: ConnectType) -> Unit>()
  private val mNetStateListener = mutableListOf<(isAvailable: Boolean) -> Unit>()
  private var mCurrentConnectType: ConnectType? = null
  private var mIsNetAvailable: Boolean? = null

  /**
     * 初始化
     */
  fun init(context: Context) {
    mConnectivityManager = context.getSystemService(ConnectivityManager::class.java)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
      mConnectivityManager?.registerDefaultNetworkCallback(DefaultNetConnectCallback())
    } else {
      context.registerReceiver(
        NetConnectReceiver(),
        IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
      )
    }
  }

  /**
     * 注册网络类型监听
     */
  fun addNetTypeChangeListener(listener: (type: ConnectType) -> Unit) {
    mNetTypeListener.add(listener)
  }

  /**
     * 反注册网络类型监听
     */

  fun removeNetTypeChangeListener(listener: (type: ConnectType) -> Unit) {
    mNetTypeListener.remove(listener)
  }

  /**
     * 注册网络状态监听
     */
  fun addNetStatusChangeListener(listener: (isAvailable: Boolean) -> Unit) {
    mNetStateListener.add(listener)
  }

  /**
     * 反注册网络状态监听
     */
  fun removeNetStatusChangeListener(listener: (isAvailable: Boolean) -> Unit) {
    mNetStateListener.remove(listener)
  }

  /**
     * 获取当前网络类型
     */
  fun getConnectType(): ConnectType {
    if (mConnectivityManager == null) {
      throw UninitializedPropertyAccessException("请先调用init()初始化")
    }
    return mCurrentConnectType ?: mConnectivityManager?.getNetworkCapabilities(
      mConnectivityManager?.activeNetwork
    ).let {
      return if (it?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true) {
        ConnectType.Mobile
      } else if (it?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true) {
        ConnectType.Wifi
      } else {
        ConnectType.None
      }
    }
  }

  /**
     * 获取当前是否网络已连接
     */
  fun isConnected(): Boolean {
    if (mConnectivityManager == null) {
      throw UninitializedPropertyAccessException("请先调用init()初始化")
    }
    return (mIsNetAvailable
                ?: mConnectivityManager?.getNetworkCapabilities(mConnectivityManager?.activeNetwork)
                ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) == true
  }

  private class DefaultNetConnectCallback : ConnectivityManager.NetworkCallback() {

    override fun onLost(network: Network) {
      super.onLost(network)
      mCurrentConnectType = ConnectType.None
      mainHandler.postDelayed({
        if (mCurrentConnectType == ConnectType.None && mIsNetAvailable == true) {
          mIsNetAvailable = false
          mNetStateListener.forEach { it.invoke(false) }
          mNetTypeListener.forEach { it(ConnectType.None) }
        }
      }, 500)
    }

    override fun onCapabilitiesChanged(
      network: Network,
      networkCapabilities: NetworkCapabilities
    ) {
      super.onCapabilitiesChanged(network, networkCapabilities)
      mainHandler.post {
        val isConnected =
        networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
        val isCellular =
        networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
        val isWifi =
        networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)

        if (isConnected) {
          val newConnectType =
          if (isCellular) ConnectType.Mobile else if (isWifi) ConnectType.Wifi else ConnectType.None
          if (mIsNetAvailable == null || mIsNetAvailable == false) {
            mIsNetAvailable = true
            mNetStateListener.forEach { it(true) }
          }
          if (mCurrentConnectType != newConnectType) {
            mCurrentConnectType = newConnectType
            mNetTypeListener.forEach { it(newConnectType) }
          }
        }
      }
    }
  }

  private class NetConnectReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
      val activityNetworkInfo =
      context?.getSystemService(ConnectivityManager::class.java)?.allNetworkInfo?.filter {
        (it.type == ConnectType.Mobile.value || it.type == ConnectType.Wifi.value) && it.isConnected
      }?.firstOrNull()
      if (activityNetworkInfo != null) {
        if (mIsNetAvailable == null || mIsNetAvailable == false) {
          mIsNetAvailable = true
          mNetStateListener.forEach { it(true) }
        }
        ConnectType.convert2Type(activityNetworkInfo.type).let { connectType ->
          if (connectType != mCurrentConnectType) {
            mCurrentConnectType = connectType
            mNetTypeListener.forEach { it(connectType) }
          }
        }
        return
      }
      mCurrentConnectType = ConnectType.None
      mainHandler.postDelayed({
        if (mCurrentConnectType == ConnectType.None && mIsNetAvailable == true) {
          mIsNetAvailable = false
          mNetStateListener.forEach { it(false) }
          mNetTypeListener.forEach { it(ConnectType.None) }
        }
      }, 500)

    }
  }
}

效果:

测试代码:

kotlin 复制代码
class MainActivity : AppCompatActivity(){
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    Log.e("qingshan", "网络是否连接= ${NetConnectManager.isConnected()} & 网络类型= ${NetConnectManager.getConnectType()}")
    NetConnectManager.addNetTypeChangeListener {
      Log.e("qingshan", "网络类型[监听]= $it")
    }
    NetConnectManager.addNetStatusChangeListener {
      Log.e("qingshan", "网络是否已连接[监听]= $it")
    }
  }
}
  • 数据流量、wifi 全关,冷启动。
kotlin 复制代码
qingshan   E  网络是否连接= false & 网络类型= com.stefan.simpleskin.ConnectType$None@6f21c25
  • 数据流量、wifi 全开,冷启动。
kotlin 复制代码
qingshan   E  网络是否连接= true & 网络类型= com.stefan.simpleskin.ConnectType$Wifi@34771fa
qingshan   E  网络类型[监听]= com.stefan.simpleskin.ConnectType$Wifi@34771fa
  • 数据流量、wifi 全开,仅关闭流量。 无监听回调。
  • 数据流量、wifi 全开,仅关闭wifi(用于模拟断开wifi 或 wifi网络不佳时系统自动启用数据流量)。
kotlin 复制代码
qingshan   E  网络类型[监听]= com.stefan.simpleskin.ConnectType$Mobile@cf38ed1
  • 数据流量、wifi 全关。
kotlin 复制代码
qingshan   E  网络是否已连接[监听]= false
qingshan   E  网络类型[监听]= com.stefan.simpleskin.ConnectType$None@fddad36
  • 仅开数据流量,再开 wifi(用于模拟使用过程中自动连接上wifi)。
kotlin 复制代码
qingshan   E  网络类型[监听]= com.stefan.simpleskin.ConnectType$Wifi@34771fa
  • 仅开wifi,再开数据流量。无监听回调。

参考内容:

读取网络状态 | Connectivity | Android Developers


Hi,我是"青杉",您可以通过如下方式关注我:

相关推荐
烬奇小云2 小时前
认识一下Unicorn
android·python·安全·系统安全
顾北川_野15 小时前
Android 进入浏览器下载应用,下载的是bin文件无法安装,应为apk文件
android
CYRUS STUDIO15 小时前
Android 下内联汇编,Android Studio 汇编开发
android·汇编·arm开发·android studio·arm
右手吉他15 小时前
Android ANR分析总结
android
PenguinLetsGo17 小时前
关于 Android15 GKI2407R40 导致梆梆加固软件崩溃
android·linux
杨武博19 小时前
音频格式转换
android·音视频
音视频牛哥21 小时前
Android音视频直播低延迟探究之:WLAN低延迟模式
android·音视频·实时音视频·大牛直播sdk·rtsp播放器·rtmp播放器·android rtmp
ChangYan.21 小时前
CondaError: Run ‘conda init‘ before ‘conda activate‘解决办法
android·conda
二流小码农21 小时前
鸿蒙开发:ForEach中为什么键值生成函数很重要
android·ios·harmonyos
夏非夏1 天前
Android 生成并加载PDF文件
android