Android网络状态获取及NetworkCallback简述
前言
在APP的开发中,获取到网络的链接状态是一个经常使用到的方法。除了可以使用ping
指令来判断当前的网络状况之外,还可以直接通过ConnectivityManager
来对网络状态进行判断。
一、网络判断旧方法(deprecated)
权限申请
如果要获取网络信息,首先是需要申请网络权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
判断网络
使用ConnectivityManager
可以十分方便的直接判断网络,调用方法如下:
//判断网络是否连接
fun isNetworkConnected(context: Context?): Boolean {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val mNetworkInfo = mConnectivityManager.activeNetworkInfo
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable
}
}
return false
}
//判断WiFi是否连接
fun isWifiConnected(context: Context?): Boolean {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val mWiFiNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
if (mWiFiNetworkInfo != null) {
return mWiFiNetworkInfo.isAvailable
}
}
return false
}
//判断移动网络是否连接
fun isMobileConnected(context: Context?): Boolean {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val mMobileNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
if (mMobileNetworkInfo != null) {
return mMobileNetworkInfo.isAvailable
}
}
return false
}
//获取连接网络的网络信息
fun getConnectedType(context: Context?): Int {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val mNetworkInfo = mConnectivityManager.activeNetworkInfo
if (mNetworkInfo != null && mNetworkInfo.isAvailable) {
return mNetworkInfo.type
}
}
return -1
}
但是在完成代码之后却发现有些方法已经被标记为deprecated
了,如isAvailable()
和getActiveNetworkInfo()
方法。查看代码注释,其中提示我们应该使用ConnectivityManager.NetworkCallback
去监听网络连接变化,并使用registerNetworkCallback
去注册监听,内容如下:
* @deprecated Apps should instead use the
* {@link android.net.ConnectivityManager.NetworkCallback} API to
* learn about connectivity changes.
* {@link ConnectivityManager#registerDefaultNetworkCallback} and
* {@link ConnectivityManager#registerNetworkCallback}. These will
* give a more accurate picture of the connectivity state of
* the device and let apps react more easily and quickly to changes.
接下来,我们对此网络监听api进行简单说明。
二、网络监听
ConnectivityManager.NetworkCallback
是一个抽象类,具有如下几个方法:
方法 | 描述 |
---|---|
onAvailable(network: Network) | 网络连接成功回调 |
onUnavailable() | 网络连接超时或网络不可达 |
onLost(Network network) | 网络已断开连接 |
onLosing(Network network, int maxMsToLive) | 网络正在丢失连接 |
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) | 网络状态变化 |
onLinkPropertiesChanged(Network network, LinkProperties linkProperties) | 网络连接属性变化 |
onBlockedStatusChanged(Network network, boolean blocked) | 访问的网络阻塞状态发生变化 |
其中最为常用的方法为onAvailable
,onLost
,onCapabilitiesChanged
方法。
我们定义一个继承自ConnectivityManager.NetworkCallback
的子类:NetUtil
,示例代码如下:
package com.example.demowork1.util
import android.content.Context
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
class NetUtil: ConnectivityManager.NetworkCallback() {
//网络连接成功
override fun onAvailable(network: Network) {
LogUtil.instance.d("网络连接成功")
super.onAvailable(network)
}
//网络已断开连接
override fun onLost(network: Network) {
LogUtil.instance.d("网络已断开连接")
super.onLost(network)
}
override fun onLosing(network: Network, maxMsToLive: Int) {
LogUtil.instance.d("网络正在断开连接")
super.onLosing(network, maxMsToLive)
}
//无网络
override fun onUnavailable() {
LogUtil.instance.d("网络连接超时或者网络连接不可达")
super.onUnavailable()
}
//当网络状态修改(网络依然可用)时调用
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)
LogUtil.instance.d( "net status change! 网络连接改变")
}
//当访问的网络被阻塞或者解除阻塞时调用
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
super.onBlockedStatusChanged(network, blocked)
}
//当网络连接属性发生变化时调用
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
super.onLinkPropertiesChanged(network, linkProperties)
}
...
}
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)
是我们较为常用的网络状态发生变化时的监听,其中的参数networkCapabilities
包含有一些我们常用的api ,其中保罗有两个重要方法,如下:
- hasCapability
- hasTransport
hasCapability
可以判断网络是否连接,有多个参数(参数可以查看接口NetCapability
),其中常用参数如下:
参数 | 说明 |
---|---|
NetworkCapabilities.NET_CAPABILITY_INTERNET | 表示是否连接上了互联网(不关心是否可以上网) |
NetworkCapabilities.NET_CAPABILITY_VALIDATED | 表示能够和互联网通信(这个为true表示能够上网) |
hasTransport
可以判断网络的类型,同样有多个参数(参数可以查看接口Transport
),其中常用的参数如下:
参数 | 说明 |
---|---|
TRANSPORT_WIFI | 表示接入的是WIFI网络 |
TRANSPORT_CELLULAR | 表示接入的是数据网络 |
TRANSPORT_BLUETOOTH | 表示接入的是蓝牙 |
具体的调用示例如下:
//当网络状态修改(网络依然可用)时调用
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)
LogUtil.instance.d( "net status change! 网络连接改变")
// 表明此网络连接成功验证
if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
// 使用WI-FI
LogUtil.instance.d("当前在使用WiFi上网")
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
// 使用数据网络
LogUtil.instance.d("当前在使用数据网络上网")
} else{
LogUtil.instance.d("当前在使用其他网络")
// 未知网络,包括蓝牙、VPN等
}
}
}
监听调用
具体的调用实现如下:
private fun setNetListener() {
var request = NetworkRequest.Builder().build()
var connMgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connMgr.registerNetworkCallback(request, NetUtil.instance)
}
三、 同步网络状态获取
需要注意的是,虽然Google提供了此Callback方法来获取网络状态的,但是此回调是异步的,如果需要同步获取网络状态,需要调用如下方法getNetworkCapabilities(Network network)
方法来获取当前NetWork的连接状态,示例代码如下:
val network = mConnectivityManager.activeNetwork ?: return false
val status = mConnectivityManager.getNetworkCapabilities(network)
?: return false
if (status.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
return true
}
但是此方法是出现在Android M之后的SDK中,所以同步获取网络连接状态的代码还需要对Android的版本进行判断,最终代码如下:
/**
* 判断网络是否连接
*/
fun isNetworkConnected(context: Context?): Boolean {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
val mNetworkInfo = mConnectivityManager.activeNetworkInfo
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable
}
} else {
val network = mConnectivityManager.activeNetwork ?: return false
val status = mConnectivityManager.getNetworkCapabilities(network)
?: return false
if (status.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
return true
}
}
}
return false
}
/**
* 判断是否是WiFi连接
*/
fun isWifiConnected(context: Context?): Boolean {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
val mWiFiNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
if (mWiFiNetworkInfo != null) {
return mWiFiNetworkInfo.isAvailable
}
} else {
val network = mConnectivityManager.activeNetwork ?: return false
val status = mConnectivityManager.getNetworkCapabilities(network)
?: return false
if (status.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return true
}
}
}
return false
}
/**
* 判断是否是数据网络连接
*/
fun isMobileConnected(context: Context?): Boolean {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
val mMobileNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
if (mMobileNetworkInfo != null) {
return mMobileNetworkInfo.isAvailable
}
} else {
val network = mConnectivityManager.activeNetwork ?: return false
val status = mConnectivityManager.getNetworkCapabilities(network)
?: return false
status.transportInfo
if (status.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return true
}
}
}
return false
}
总结
本文主要是对于获取网络状态以及网络监听进行说明,需要注意的是对于同步和异步的区分。