【问题标题】:activeNetworkInfo.type is deprecated in API level 28在 API 级别 28 中不推荐使用 activeNetworkInfo.type
【发布时间】:2019-05-01 03:01:18
【问题描述】:

我想使用连接管理器,它提供方法activeNetworkInfo.type 来检查Android 中的网络类型。此方法在 API 级别 28 中已弃用。那么在 API 28 中检查网络类型的解决方案是什么。我的代码是:

/**
 * Check Wi Fi connectivity
 */
fun isWiFiConnected(context: Context): Boolean {
    val connManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    return connManager.activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI
}

我的 Gradle 是这样的:

compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28
    }

【问题讨论】:

标签: android kotlin deprecated android-connectivitymanager


【解决方案1】:

更新

The connectivityManager.activeNetworkInfo is also deprecated in API level 29

现在我们需要使用ConnectivityManager.NetworkCallback API or ConnectivityManager#getNetworkCapabilities or ConnectivityManager#getLinkProperties

使用ConnectivityManager#getNetworkCapabilities的示例代码

private fun isInternetAvailable(context: Context): Boolean {
        var result = false
        val connectivityManager =
            context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val networkCapabilities = connectivityManager.activeNetwork ?: return false
            val actNw =
                connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
            result = when {
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                else -> false
            }
        } else {
            connectivityManager.run {
                connectivityManager.activeNetworkInfo?.run {
                    result = when (type) {
                        ConnectivityManager.TYPE_WIFI -> true
                        ConnectivityManager.TYPE_MOBILE -> true
                        ConnectivityManager.TYPE_ETHERNET -> true
                        else -> false
                    }

                }
            }
        }

        return result
    }

旧答案

Yes getType() is deprecated in API level 28

现在我们需要使用调用者应该切换到检查NetworkCapabilities.hasTransport(int)

还有 getAllNetworkInfo() is deprecated in API level 29

现在我们需要使用getAllNetworks() 而不是getNetworkInfo(android.net.Network)

getNetworkInfo()

  • 返回有关特定网络的连接状态信息。

getAllNetworks()

  • 返回框架当前跟踪的所有网络的数组。

示例代码

fun isWiFiConnected(context: Context): Boolean {
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        val network = connectivityManager.activeNetwork
        val capabilities = connectivityManager.getNetworkCapabilities(network)
        capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
    } else {
        connectivityManager.activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI
    }
}

完整代码

@Suppress("DEPRECATION")
fun isInternetAvailable(context: Context): Boolean {
    var result = false
    val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        cm?.run {
            cm.getNetworkCapabilities(cm.activeNetwork)?.run {
                result = when {
                    hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                    hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                    hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                    else -> false
                }
            }
        }
    } else {
        cm?.run {
            cm.activeNetworkInfo?.run {
                if (type == ConnectivityManager.TYPE_WIFI) {
                    result = true
                } else if (type == ConnectivityManager.TYPE_MOBILE) {
                    result = true
                }
            }
        }
    }
    return result
}

【讨论】:

  • @kkarakk 你确定吗? docs 中没有弃用的迹象
  • 我现在如何检查设备是否有互联网连接?到目前为止,它只是 connectivityManager.activeNetworkInfo?.isConnected == true 。我们现在应该做什么?只是connectivityManager.activeNetwork != null ?
  • 代码不起作用。我没有 SIM 卡,但我通过 Wifi 上网。 isInternetAvailable()hasTransport(NetworkCapabilities.TRANSPORT_WIFI) 返回 false。
  • @ranasaha 抱歉回复晚了,现在我们需要使用ConnectivityManager#getNetworkCapabilities 请检查更新的答案我已经使用ConnectivityManager#getNetworkCapabilities 添加了示例代码
  • @NileshRathod 在您实例化您的 actNw 变量之后,并且在您检查网络功能之前,您应该添加空检查。 getNetworkCapabilities 可以为空。
【解决方案2】:

稍微简单的版本(minSdkVersion 23+)

fun isNetworkAvailable(context: Context) =
    (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).run {
        getNetworkCapabilities(activeNetwork)?.run {
            hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                || hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                || hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
        } ?: false
    }

【讨论】:

  • 完美答案!
  • 这是最佳答案
【解决方案3】:

这是我对 SDK 29 的解决方案:一个名为 NetworkWatcher 的类,它观察网络的变化。它提供了诸如isWifiOn 之类的原始变量,以及通过FlowLiveData 观察网络随时间变化的选项。

@ExperimentalCoroutinesApi
class NetworkWatcher
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
private constructor(
    application: Application
) {

    private val connectivityManager =
        application.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
                as ConnectivityManager

    // general availability of Internet over any type
    var isOnline = false
        get() {
            updateFields()
            return field
        }

    var isOverWifi = false
        get() {
            updateFields()
            return field
        }

    var isOverCellular = false
        get() {
            updateFields()
            return field
        }

    var isOverEthernet = false
        get() {
            updateFields()
            return field
        }

    companion object {
        @Volatile
        private var INSTANCE: NetworkWatcher? = null

        fun getInstance(application: Application): NetworkWatcher {
            synchronized(this) {
                if (INSTANCE == null) {
                    INSTANCE = NetworkWatcher(application)
                }
                return INSTANCE!!
            }
        }
    }

    @Suppress("DEPRECATION")
    private fun updateFields() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            val networkAvailability =
                connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)

            if (networkAvailability != null &&
                networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
                networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
            ) {
                //has network
                isOnline = true

                // wifi
                isOverWifi =
                    networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)

                // cellular
                isOverCellular =
                    networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)

                // ethernet
                isOverEthernet =
                    networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
            } else {
                isOnline = false
                isOverWifi = false
                isOverCellular = false
                isOverEthernet = false
            }
        } else {

            val info = connectivityManager.activeNetworkInfo
            if (info != null && info.isConnected) {
                isOnline = true

                val wifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
                isOverWifi = wifi != null && wifi.isConnected

                val cellular = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
                isOverCellular = cellular != null && cellular.isConnected

                val ethernet = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET)
                isOverEthernet = ethernet != null && ethernet.isConnected

            } else {
                isOnline = false
                isOverWifi = false
                isOverCellular = false
                isOverEthernet = false
            }
        }
    }

    fun watchNetwork(): Flow<Boolean> = watchWifi()
        .combine(watchCellular()) { wifi, cellular -> wifi || cellular }
        .combine(watchEthernet()) { wifiAndCellular, ethernet -> wifiAndCellular || ethernet }

    fun watchNetworkAsLiveData(): LiveData<Boolean> = watchNetwork().asLiveData()

    fun watchWifi(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_WIFI)

    fun watchWifiAsLiveData() = watchWifi().asLiveData()

    fun watchCellular(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_CELLULAR)

    fun watchCellularAsLiveData() = watchCellular().asLiveData()

    fun watchEthernet(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_ETHERNET)

    fun watchEthernetAsLiveData() = watchEthernet().asLiveData()

    private fun callbackFlowForType(@IntRange(from = 0, to = 7) type: Int) = callbackFlow {

        offer(false)

        val networkRequest = NetworkRequest.Builder()
            .addTransportType(type)
            .build()

        val callback = object : ConnectivityManager.NetworkCallback() {
            override fun onLost(network: Network?) {
                offer(false)
            }

            override fun onUnavailable() {
                offer(false)
            }

            override fun onLosing(network: Network?, maxMsToLive: Int) {
                // do nothing
            }

            override fun onAvailable(network: Network?) {
                offer(true)
            }
        }

        connectivityManager.registerNetworkCallback(networkRequest, callback)

        awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
    }
}

例如,您可以在应用程序中订阅有关手机网络状态的更新,例如:

GlobalScope.launch {
    NetworkWatcher.getInstance(this@MyApplication).watchNetwork().collect { connected ->
        Log.d("TAG", "Network In App: $connected")
    }
}

或者要回答您的问题,只需阅读 Wifi 值,例如:

if (NetworkWatcher.getInstance(this@BaseApp).isOverWifi) {
    // do stuff
}

旁注:我没有一直使用getInstance(),而是使用Koin 等DI 框架将NetworkWatcher 注入到我需要的地方。

【讨论】:

  • 太好了!!
【解决方案4】:

我只是想知道,无论连接类型如何,设备是否已连接到互联网:

@Suppress("DEPRECATION")
fun isOnline(context: Context?): Boolean {
    var connected = false
    @Suppress("LiftReturnOrAssignment")
    context?.let {
        val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val networkCapabilities = cm.activeNetwork ?: return false
            val actNw = cm.getNetworkCapabilities(networkCapabilities) ?: return false
            connected = actNw.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        } else {
            val netInfo = cm.activeNetworkInfo
            connected = netInfo?.isConnectedOrConnecting == true
        }
    }
    return connected
}

【讨论】:

    【解决方案5】:

    不,从这里看:https://developer.android.com/reference/android/net/ConnectivityManager.html#getActiveNetworkInfo()

    getActiveNetworkInfo() 在 Android API 28 中仍然可用,并且没有任何地方说它已被弃用。

    但不推荐使用的是 NetworkInfo 类的getType()

    https://developer.android.com/reference/android/net/NetworkInfo#getType()

    此方法在 API 级别 28 中已弃用。

    调用者应该切换到检查 NetworkCapabilities.hasTransport(int) 而不是其中之一 NetworkCapabilities#TRANSPORT_* constants : getType()getTypeName() 无法解释使用多个传输的网络。 请注意,通常应用程序不应该关心传输; NetworkCapabilities.NET_CAPABILITY_NOT_METEREDNetworkCapabilities.getLinkDownstreamBandwidthKbps() 是调用 应该关注计量或带宽的应用程序,因为 他们提供的信息更加准确。

    【讨论】:

    • 弃用 API 的替换方法在官方 API 文档中,我附在上面。
    • getActiveNetworkInfo() 在 API 29 中已弃用。我认为您应该更新您的答案
    • 我不明白该使用什么,以防我只想知道是否有 Internet 连接。到目前为止,我只是使用这个:connectivityManager.activeNetworkInfo?.isConnected == true。我们现在应该使用:connectivityManager.activeNetwork != null 吗?
    【解决方案6】:

    Java 代码:

    public static boolean isConnectingToInternet(Context mContext) {
        if (mContext == null) return false;
    
        ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                final Network network = connectivityManager.getActiveNetwork();
                if (network != null) {
                    final NetworkCapabilities nc = connectivityManager.getNetworkCapabilities(network);
    
                    return (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                            nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
                }
            } else {
                NetworkInfo[] networkInfos = connectivityManager.getAllNetworkInfo();
                for (NetworkInfo tempNetworkInfo : networkInfos) {
                    if (tempNetworkInfo.isConnected()) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    

    【讨论】:

      【解决方案7】:

      我正在使用这个 Kotlin 函数来检查互联网连接:

      注意版本检查(版本>= M)

      private fun isInternetConnected():Boolean{
      
          val connectivityManager = this.getSystemService(android.content.Context.CONNECTIVITY_SERVICE)
                  as ConnectivityManager
      
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
              val networkCapabilities = connectivityManager.activeNetwork ?: return false
              val activeNetwork = connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
      
              return when {
      
                  activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                          activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ||
                          activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                  else -> false
              }
          }
          else {
              return connectivityManager.activeNetworkInfo != null &&
                      connectivityManager.activeNetworkInfo!!.isConnectedOrConnecting
          }
      }
      

      【讨论】:

        【解决方案8】:

        这是旧/新 api 两种方法的 Kotlin 实现:

        @Suppress("DEPRECATION")
        fun isConnectedOld(context: Context): Boolean {
            val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            val networkInfo = connManager.activeNetworkInfo
            return networkInfo.isConnected
        
        }
        
        
        @RequiresApi(Build.VERSION_CODES.M)
        fun isConnectedNewApi(context: Context): Boolean {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
            return capabilities?.hasCapability(NET_CAPABILITY_INTERNET) == true
        }
        

        及常用方法:

        fun isConnected(context: Context): Boolean {
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                isConnectedNewApi(context)
            } else{
                isConnectedOld(context)
            }
        }
        

        【讨论】:

          【解决方案9】:

          我已根据我的需要改编了 Nilesh Rathod 的答案:

          enum class ConnectivityMode {
              NONE,
              WIFI,
              MOBILE,
              OTHER,
              MAYBE
          }
          
          var connectivityMode = ConnectivityMode.NONE
          
          private fun checkConnectivity(context: Context): ConnectivityMode {
          
              val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
          
              cm?.run {
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                      getNetworkCapabilities(activeNetwork)?.run {
                          return when {
                              hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> ConnectivityMode.WIFI
                              hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> ConnectivityMode.MOBILE
                              hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> ConnectivityMode.OTHER
                              hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> ConnectivityMode.MAYBE
                              else -> ConnectivityMode.NONE
                          }
                      }
                  } else {
                      @Suppress("DEPRECATION")
                      activeNetworkInfo?.run {
                          return when (type) {
                              ConnectivityManager.TYPE_WIFI -> ConnectivityMode.WIFI
                              ConnectivityManager.TYPE_MOBILE -> ConnectivityMode.MOBILE
                              ConnectivityManager.TYPE_ETHERNET -> ConnectivityMode.OTHER
                              ConnectivityManager.TYPE_BLUETOOTH -> ConnectivityMode.MAYBE
                              else -> ConnectivityMode.NONE
                          }
                      }
                  }
              }
              return ConnectivityMode.NONE
          }
          

          然后我用okhttp检查连接:

          fun updateData(manual: Boolean, windowContext: Context) = runBlocking {
              connectivityMode = checkConnectivity(MyApplication.context)
              if (connectivityMode != ConnectivityMode.NONE) {
                  val conn : Boolean = GlobalScope.async {
                      var retval = false
                      try {
                          val request = Request.Builder().url(WORK_URL).build()
                          val response =  client.newCall(request).execute()
                          Log.i(TAG, "code = ${response?.code}")
                          if (response?.code == 200) {
                              // I use the response body since it is a small file and already downloaded
                              val input = response.body?.byteStream()
                              if (input != null) {
                                  // do stuff
                                  response.body?.close()
                                  retval = true
                              }
                          }
                      }
                      catch(exception: Exception) {
                          Log.e(TAG, "error ${exception.message ?: ""}")
                      }
                      retval
                  }.await()
                  if (!conn) {
                      connectivityMode = ConnectivityMode.NONE
                  }
              }
              ....
          

          【讨论】:

            【解决方案10】:

            我希望这对你有用! 此代码适用于 api 21 及更高版本

            //创建一个新类并添加以下内容

            public class CheckNetwork {
            
            public static boolean isNetworkConnected;
            private Context context;
            
            public CheckNetwork(Context context) {
                this.context = context;
            }
            
            public boolean isOnline(){
                isNetworkConnected = false;
                ConnectivityManager connectivityMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                Network[] allNetworks = connectivityMgr.getAllNetworks(); // added in API 21 (Lollipop)
            
                for (Network network : allNetworks) {
                    NetworkCapabilities networkCapabilities = connectivityMgr.getNetworkCapabilities(network);
                    if (networkCapabilities != null) {
                        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                                || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                                || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
                            isNetworkConnected = true;
                        }
                    }
                return isNetworkConnected;
                }
            

            }

            //在MainActivity中

            CheckNetwork myNetwork = new CheckNetwork(this);
            

            //在 OnCreateMethod 中

            myNetwork.isOnline();
                if (myNetwork.isNetworkConnected){
                    Toast.makeText(this, "Please check your Internet Connection", Toast.LENGTH_SHORT).show();
                }else {
                    Toast.makeText(this, "Your Internet Connction is Ok", Toast.LENGTH_SHORT).show();
                }
            

            【讨论】:

            • 唯一对我有用的东西,因为我正在使用目标 API 30,并且因为 NetworkInfo 方法在 API 28 中已弃用。
            • \\您节省了我的时间.. 非常感谢 :)
            【解决方案11】:

            如果您使用最低 API 级别 23,则可以使用这个缩短的 Kotlin 版本。

            fun isNetworkAvailable(context: Context): Boolean {
                (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).apply {
                    return getNetworkCapabilities(activeNetwork)?.run {
                        when {
                            hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                            hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                            hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                            else -> false
                        }
                    } ?: false
                }
            }
            

            【讨论】:

              【解决方案12】:

              最近我不得不编写一个小函数来检查我的单一 WebView 中的网络连接。我还注意到 API 有了很大的发展,特别是当 Kotlin 出现时,找到有效的参考需要几分钟。

              这是我的 NetworkConnectivityManager 小类,它具有检查网络可用性的简单功能。

              import android.content.Context
              import android.content.Context.CONNECTIVITY_SERVICE
              import android.net.ConnectivityManager
              import android.net.NetworkCapabilities
              import android.os.Build
              
              class NetworkConnectivityManager(context: Context) {
                  private val connectivityManager =
                      context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
              
                  @Suppress("DEPRECATION")
                  fun isNetworkAvailable(): Boolean {
                      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                          val nc = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
              
                          nc != null 
                                  && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                                  && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                      }
              
                      val networkInfo = connectivityManager.activeNetworkInfo
                      return networkInfo != null && networkInfo.isConnected
                  }
              }
              

              【讨论】:

                【解决方案13】:

                完整的解决方案 在包中创建这些类让我们说连接

                1. 接口 ConnectivityProvider

                导入 android.content.Context 导入 android.content.Context.CONNECTIVITY_SERVICE 导入 android.net.ConnectivityManager

                import android.net.NetworkCapabilities
                import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
                
                import android.net.NetworkInfo
                import android.os.Build
                
                import androidx.annotation.RequiresApi
                
                interface ConnectivityProvider {
                    interface ConnectivityStateListener {
                        fun onStateChange(state: NetworkState)
                    }
                
                fun addListener(listener: ConnectivityStateListener)
                fun removeListener(listener: ConnectivityStateListener)
                
                fun getNetworkState(): NetworkState
                
                @Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
                sealed class NetworkState {
                    object NotConnectedState : NetworkState()
                
                    sealed class ConnectedState(val hasInternet: Boolean) : NetworkState() {
                
                        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
                        data class Connected(val capabilities: NetworkCapabilities) : ConnectedState(
                            capabilities.hasCapability(NET_CAPABILITY_INTERNET)
                        )
                
                        @Suppress("DEPRECATION")
                        data class ConnectedLegacy(val networkInfo: NetworkInfo) : ConnectedState(
                            networkInfo.isConnectedOrConnecting
                        )
                    }
                }
                
                companion object {
                    fun createProvider(context: Context): ConnectivityProvider {
                        val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
                        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            ConnectivityProviderImpl(cm)
                        } else {
                            ConnectivityProviderLegacyImpl(context, cm)
                        }
                    }
                }
                

                }

                1. 抽象类ConnectivityProviderBaseImpl

                   abstract class ConnectivityProviderBaseImpl : ConnectivityProvider {
                   private val handler = Handler(Looper.getMainLooper())
                   private val listeners = mutableSetOf<ConnectivityStateListener>()
                   private var subscribed = false
                  
                   override fun addListener(listener: ConnectivityStateListener) {
                       listeners.add(listener)
                       listener.onStateChange(getNetworkState()) // propagate an initial state
                       verifySubscription()
                   }
                  
                   override fun removeListener(listener: ConnectivityStateListener) {
                       listeners.remove(listener)
                       verifySubscription()
                   }
                  
                   private fun verifySubscription() {
                       if (!subscribed && listeners.isNotEmpty()) {
                           subscribe()
                           subscribed = true
                       } else if (subscribed && listeners.isEmpty()) {
                           unsubscribe()
                           subscribed = false
                       }
                   }
                  
                   protected fun dispatchChange(state: NetworkState) {
                       handler.post {
                           for (listener in listeners) {
                               listener.onStateChange(state)
                           }
                       }
                   }
                  
                   protected abstract fun subscribe()
                   protected abstract fun unsubscribe()
                  

                  }

                2. 类 ConnectivityProviderImpl

                @RequiresApi(Build.VERSION_CODES.N)

                class ConnectivityProviderImpl(private val cm: ConnectivityManager) :
                    ConnectivityProviderBaseImpl() {
                
                    private val networkCallback = ConnectivityCallback()
                
                    override fun subscribe() {
                        cm.registerDefaultNetworkCallback(networkCallback)
                    }
                
                    override fun unsubscribe() {
                        cm.unregisterNetworkCallback(networkCallback)
                    }
                
                    override fun getNetworkState(): NetworkState {
                        val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
                        return if (capabilities != null) {
                            Connected(capabilities)
                        } else {
                            NotConnectedState
                        }
                    }
                
                    private inner class ConnectivityCallback : NetworkCallback() {
                
                        override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
                            dispatchChange(Connected(capabilities))
                        }
                
                        override fun onLost(network: Network) {
                            dispatchChange(NotConnectedState)
                        }
                    }
                }
                
                1. 类 ConnectivityProviderLegacyImpl

                @Suppress("弃用")

                class ConnectivityProviderLegacyImpl(
                private val context: Context,
                 private val cm: ConnectivityManager
                ) : ConnectivityProviderBaseImpl() {
                
                    private val receiver = ConnectivityReceiver()
                
                    override fun subscribe() {
                        context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
                    }
                
                    override fun unsubscribe() {
                        context.unregisterReceiver(receiver)
                    }
                
                    override fun getNetworkState(): NetworkState {
                        val activeNetworkInfo = cm.activeNetworkInfo
                        return if (activeNetworkInfo != null) {
                            ConnectedLegacy(activeNetworkInfo)
                        } else {
                            NotConnectedState
                        }
                    }
                
                    private inner class ConnectivityReceiver : BroadcastReceiver() {
                        override fun onReceive(c: Context, intent: Intent) {
                            // on some devices ConnectivityManager.getActiveNetworkInfo() does not provide the correct network state
                            // https://issuetracker.google.com/issues/37137911
                            val networkInfo = cm.activeNetworkInfo
                            val fallbackNetworkInfo: NetworkInfo? = intent.getParcelableExtra(EXTRA_NETWORK_INFO)
                            // a set of dirty workarounds
                            val state: NetworkState =
                                if (networkInfo?.isConnectedOrConnecting == true) {
                                    ConnectedLegacy(networkInfo)
                                } else if (networkInfo != null && fallbackNetworkInfo != null &&
                                    networkInfo.isConnectedOrConnecting != fallbackNetworkInfo.isConnectedOrConnecting
                                ) {
                                    ConnectedLegacy(fallbackNetworkInfo)
                                } else {
                                    val state = networkInfo ?: fallbackNetworkInfo
                                    if (state != null) ConnectedLegacy(state) else NotConnectedState
                                }
                            dispatchChange(state)
                        }
                    }
                }
                

                用法:- 家庭活动

                class HomeActivity : BaseActivity(), ConnectivityProvider.ConnectivityStateListener {
                    val provider: ConnectivityProvider by lazy { ConnectivityProvider.createProvider(this@HomeActivity) }
                 override fun onStart() {
                        super.onStart()
                        provider.addListener(this)
                    }
                
                override fun onStop() {
                    super.onStop()
                    provider.removeListener(this)
                }
                
                override fun onStateChange(state: ConnectivityProvider.NetworkState) {
                    val hasInternet = state.hasInternet()
                }
                
                companion object {
                    fun ConnectivityProvider.NetworkState.hasInternet(): Boolean {
                        return (this as? ConnectivityProvider.NetworkState.ConnectedState)?.hasInternet == true
                    }
                }
                

                点击按钮或任何 api 调用

                 if(provider.getNetworkState().hasInternet()){
                                // do work    
                                }
                }
                

                如果您想在家庭活动的片段中使用检查互联网

                if ((activity as HomeActivity).provider.getNetworkState().hasInternet()) {
                            // api call
                        }
                

                【讨论】:

                  【解决方案14】:

                  对于版本&gt;= Build.VERSION_CODES.M

                  private fun isConnected(context: Context): Boolean {
                      val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
                      val capabilities = manager?.getNetworkCapabilities(manager.activeNetwork) ?: return false
                  
                      return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                              || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                              || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    在 Kotlin 中,您可以检查 Android 版本,并根据版本检查连接管理器。

                    fun Context.isInternetAvailable(): Boolean {
                        val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
                        when {
                            Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
                                val cap = cm.getNetworkCapabilities(cm.activeNetwork) ?: return false
                                return cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                            }
                            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
                                val networks = cm.allNetworks
                                for (n in networks) {
                                    val nInfo = cm.getNetworkInfo(n)
                                    if (nInfo != null && nInfo.isConnected) return true
                                }
                            }
                            else -> {
                                val networks = cm.allNetworkInfo
                                for (nInfo in networks) {
                                    if (nInfo != null && nInfo.isConnected) return true
                                }
                            }
                        }
                        return false
                    }
                    

                    在你的活动中调用扩展函数

                    if (applicationContext.isInternetAvailable()) { }
                    

                    【讨论】:

                      猜你喜欢
                      • 2016-02-08
                      • 2020-05-02
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-12-24
                      • 1970-01-01
                      相关资源
                      最近更新 更多