Android 网络变动监听
Android 网络监听。在小米13 Android 15上进行测试。
主要是在 application 中进行添加,应用生命周期内需要一直监听网络的连接和断开。
Application 中使用方式
简单使用:
import android.app.Application
import android.util.Logclass MyApp : Application(){private var mNetworkMonitor: NetworkMonitor? = nulloverride fun onCreate() {super.onCreate()setupNetworkMonitoring()}/*** 监听网络变化* */fun setupNetworkMonitoring(){mNetworkMonitor = NetworkMonitor()mNetworkMonitor?.setOnNetworkChangeListener(object : OnNetworkChangeListener {override fun onNetworkChanged(isConnected: Boolean, type: Int) {Log.d("tag", "onNetworkChanged $isConnected, $type")}},)mNetworkMonitor?.startMonitoring(this)}override fun onTerminate() {try {mNetworkMonitor?.stopMonitoring(this)} catch (e: Exception) {// 忽略异常,可能已经自动取消注册}super.onTerminate()}
}
完整的监听。在不同的页面都可以收到全局的监听
import android.app.Application
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.util.Log
import java.lang.ref.WeakReferenceclass MyApp : Application(){companion object{private const val TAG = "MyApp"}private var mNetworkMonitor: NetworkMonitor? = null// 全局网络状态var isNetworkConnected: Boolean = falsevar currentNetworkType: Int = -1val listeners: MutableList<WeakReference<NetworkStateListener>> = mutableListOf()interface NetworkStateListener {fun onNetworkConnected()fun onNetworkDisconnected()fun onNetworkTypeChanged(type: Int)}override fun onCreate() {super.onCreate()setupNetworkMonitoring()checkInitialNetworkState();Log.d(TAG, "Application 网络监听已启动");}override fun onTerminate() {try {mNetworkMonitor?.stopMonitoring(this)} catch (e: Exception) {// 忽略异常,可能已经自动取消注册}super.onTerminate()}/*** 监听网络变化* */fun setupNetworkMonitoring(){mNetworkMonitor = NetworkMonitor()mNetworkMonitor?.setOnNetworkChangeListener(object : OnNetworkChangeListener {override fun onNetworkChanged(isConnected: Boolean, type: Int) {Log.d("tag", "onNetworkChanged $isConnected, $type")isNetworkConnected = isConnected;currentNetworkType = type;// 通知所有监听器if (isConnected) {notifyNetworkConnected();} else {notifyNetworkDisconnected();}// type 目前不用,暂时不加}},)mNetworkMonitor?.startMonitoring(this)}/*** 检查初始网络状态*/private fun checkInitialNetworkState() {val cm = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager?if (cm != null) {val activeNetwork = cm.getActiveNetworkInfo()if (activeNetwork != null && activeNetwork.isConnected()) {isNetworkConnected = truecurrentNetworkType = activeNetwork.getType()Log.i(TAG, "初始网络状态: 已连接 (" + getNetworkTypeName(currentNetworkType) + ")")} else {isNetworkConnected = falsecurrentNetworkType = -1Log.w(TAG, "初始网络状态: 断开")}}}/*** 注册网络状态监听器*/fun registerNetworkListener(listener: NetworkStateListener) {synchronized(listeners) {// 移除已经被回收的弱引用val iterator: MutableIterator<WeakReference<NetworkStateListener>> = listeners.iterator()while (iterator.hasNext()) {val ref = iterator.next()if (ref.get() == null) {iterator.remove()}}// 添加新的监听器listeners.add(WeakReference<NetworkStateListener>(listener))// 立即通知当前网络状态if (isNetworkConnected) {val cm = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager?var activeNetwork: NetworkInfo? = nullif (cm != null) {activeNetwork = cm.getActiveNetworkInfo()}if (activeNetwork != null) {listener.onNetworkConnected()}} else {listener.onNetworkDisconnected()}}}/*** 取消注册网络状态监听器*/fun unregisterNetworkListener(listener: NetworkStateListener?) {synchronized(listeners) {val iterator: MutableIterator<WeakReference<NetworkStateListener>> = listeners.iterator()while (iterator.hasNext()) {val ref = iterator.next()val l = ref.get()if (l == null || l === listener) {iterator.remove()}}}}/*** 通知所有监听器网络类型变化*/private fun notifyNetworkTypeChanged(type: Int) {synchronized(listeners) {val iterator: MutableIterator<WeakReference<NetworkStateListener>> = listeners.iterator()while (iterator.hasNext()) {val ref = iterator.next()val listener = ref.get()if (listener != null) {try {listener.onNetworkTypeChanged(type)} catch (e: java.lang.Exception) {Log.e(TAG, "通知网络类型变化时出错", e)}} else {iterator.remove()}}}}/*** 通知所有监听器网络已连接*/private fun notifyNetworkConnected() {synchronized(listeners) {val iterator: MutableIterator<WeakReference<NetworkStateListener>> = listeners.iterator()while (iterator.hasNext()) {val ref = iterator.next()val listener = ref.get()if (listener != null) {try {listener.onNetworkConnected()} catch (e: java.lang.Exception) {Log.e(TAG, "通知网络连接状态时出错", e)}} else {iterator.remove()}}}}/*** 通知所有监听器网络断开*/private fun notifyNetworkDisconnected() {synchronized(listeners) {val iterator: MutableIterator<WeakReference<NetworkStateListener>> = listeners.iterator()while (iterator.hasNext()) {val ref = iterator.next()val listener = ref.get()if (listener != null) {try {listener.onNetworkDisconnected()} catch (e: java.lang.Exception) {Log.e(TAG, "通知网络断开状态时出错", e)}} else {iterator.remove()}}}}// 公共方法获取当前网络状态fun isNetworkConnected(): Boolean {return isNetworkConnected}fun getCurrentNetworkType(): Int {return currentNetworkType}fun getCurrentNetworkTypeName(): String {return getNetworkTypeName(currentNetworkType)}private fun getNetworkTypeName(type: Int): String {when (type) {ConnectivityManager.TYPE_WIFI -> return "WiFi"ConnectivityManager.TYPE_MOBILE -> return "移动网络"ConnectivityManager.TYPE_ETHERNET -> return "以太网"else -> return "未知网络"}}}
主入口
NetworkMonitor 设置监听入口(区分 Android 版本)
import android.content.Context
import android.os.Buildclass NetworkMonitor : NetworkChangeIntf{var networkChangeIntf: NetworkChangeIntf? = nullinit {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // API 24+ 优先用 NetworkCallbacknetworkChangeIntf = NetworkChangeCallback()} else { // API < 24 用广播(兼容 API 17)/*** APK启动时,会收到一次网络变化广播,网络状态为连接。* 监听需要对这个进行处理,避免首次启动时,网络状态为连接,导致错误的网络状态回调。* */networkChangeIntf = NetworkChangeReceiver()}}override fun startMonitoring(context: Context) {networkChangeIntf?.startMonitoring(context)}override fun stopMonitoring(context: Context) {networkChangeIntf?.stopMonitoring(context)}override fun setOnNetworkChangeListener(listener: OnNetworkChangeListener) {networkChangeIntf?.setOnNetworkChangeListener(listener)}}
NetworkChangeCallback
import android.content.Context
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.RequiresApi/*** 监听网络状态变化 只兼容 Android 5.0 及以上版本* */
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class NetworkChangeCallback :NetworkChangeIntf{private var mListener: OnNetworkChangeListener? = nullprivate var networkCallback: ConnectivityManager.NetworkCallback? = nullprivate var connectivityManager: ConnectivityManager? = nullprivate var isRegistered = false// 设置回调监听器override fun setOnNetworkChangeListener(listener: OnNetworkChangeListener) {mListener = listener}override fun startMonitoring(context: Context) {if (isRegistered) {return}// 获取网络连接管理器if (connectivityManager == null) {connectivityManager = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager}networkCallback = object : ConnectivityManager.NetworkCallback() {// 网络连接成功,通知可以使用的时候调用override fun onAvailable(network: Network) {super.onAvailable(network)mListener?.onNetworkChanged(true, getTransportType(network, null))}// 当访问指定的网络被阻止或解除阻塞时调用override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {super.onBlockedStatusChanged(network, blocked)}// 当网络状态修改但仍旧是可用状态时调用override fun onCapabilitiesChanged(network: Network, networkCapabilities: android.net.NetworkCapabilities) {super.onCapabilitiesChanged(network, networkCapabilities)
// Log.d("NetworkCallback: 网络能力变化")}// 当网络连接的属性被修改时调用override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {super.onLinkPropertiesChanged(network, linkProperties)}// 当系统正在尝试断开网络连接时调用override fun onLosing(network: Network, maxMsToLive: Int) {super.onLosing(network, maxMsToLive)}// 当网络已断开连接时调用override fun onLost(network: Network) {super.onLost(network)mListener?.onNetworkChanged(false, -1)}// 当网络连接超时或网络请求达不到可用要求时调用override fun onUnavailable() {super.onUnavailable()}}networkCallback?.let { callback ->val request = NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build()connectivityManager?.registerNetworkCallback(request, callback)}isRegistered = true}override fun stopMonitoring(context: Context) {networkCallback?.let { callback ->connectivityManager?.unregisterNetworkCallback(callback)}connectivityManager = null // 清理缓存mListener = null // 清理监听器isRegistered = false}private fun getTransportType(network: Network?, networkCapabilities: NetworkCapabilities?): Int {val capabilities = networkCapabilities ?: connectivityManager?.getNetworkCapabilities(network)return when {capabilities == null -> -1capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> ConnectivityManager.TYPE_WIFIcapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> ConnectivityManager.TYPE_MOBILEcapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> ConnectivityManager.TYPE_ETHERNETelse -> -1}}
}
NetworkChangeReceiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.util.Log/*** 监听网络状态变化** APK启动时,会收到一次网络变化广播,网络状态为连接。* 监听需要对这个进行处理,避免首次启动时,网络状态为连接,导致错误的网络状态回调。** 小米13 (android 15)上测试可用* */
class NetworkChangeReceiver : BroadcastReceiver(), NetworkChangeIntf {companion object{const val TAG = "NetworkChangeReceiver"}private var mListener: OnNetworkChangeListener? = nullprivate var connectivityManager: ConnectivityManager? = nullprivate var isRegistered = false// 设置回调监听器override fun setOnNetworkChangeListener(listener: OnNetworkChangeListener) {mListener = listener}override fun onReceive(context: Context?, intent: Intent?) {if (context == null || intent == null || mListener == null) {return}if (ConnectivityManager.CONNECTIVITY_ACTION == intent.action) {// 获取网络连接管理器if (connectivityManager == null) {connectivityManager = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager}connectivityManager?.let {val activeNetwork: NetworkInfo? = it.activeNetworkInfoactiveNetwork?.let {mListener?.onNetworkChanged(it.isConnected, it.type)} ?: run {// 实测在小米13(android 15)上,网络断开时,activeNetwork 为 nullmListener?.onNetworkChanged(false, -1)}}}}private fun getNetworkTypeName(type: Int): String {when (type) {ConnectivityManager.TYPE_WIFI -> return "WIFI"ConnectivityManager.TYPE_MOBILE -> return "移动网络"ConnectivityManager.TYPE_ETHERNET -> return "以太网"else -> return "未知网络"}}override fun startMonitoring(context: Context) {if (isRegistered) {return}// 注册网络状态变化广播try {val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)context.registerReceiver(this, filter)isRegistered = true} catch (e: Exception) {e.printStackTrace()Log.e(TAG,"注册网络状态变化广播失败: ${e.message}")}}override fun stopMonitoring(context: Context) {try {context.unregisterReceiver(this)} catch (e: Exception) {e.printStackTrace()Log.e(TAG,"注销网络状态变化广播失败: ${e.message}")}connectivityManager = nullmListener = nullisRegistered = false}
}
NetUtils
import android.content.Context
import android.net.wifi.WifiManager/*** 网络工具** @author D10NG* @date on 2019-10-22 10:29*/
object NetUtils {/*** 检查当前连接的网络是否为5G WI-FI*/fun is5GWifiConnected(context: Context) : Boolean {val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManagerval wifiInfo = wifiManager.connectionInfo?: return false// 频段var frequency = 0if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP) {frequency = wifiInfo.frequency} else {val ssid = wifiInfo.ssid?: return falseif (ssid.length < 2) return falseval sid = ssid.substring(1, ssid.length -1)for (scan in wifiManager.scanResults) {if (scan.SSID == sid) {frequency = scan.frequencybreak}}}return frequency in 4900..5900}/*** 获取当前连接Wi-Fi名* # 如果没有定位权限,获取到的名字将为 unknown ssid*/fun getConnectedWifiSSID(context: Context) : String {val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManagerval wifiInfo = wifiManager.connectionInfo?: return ""return wifiInfo.ssid.substring(1, wifiInfo.ssid.length -1)}
}
NetworkChangeIntf
import android.content.Contextinterface NetworkChangeIntf {fun startMonitoring(context: Context)fun stopMonitoring(context: Context)fun setOnNetworkChangeListener(listener: OnNetworkChangeListener)
}
OnNetworkChangeListener
interface OnNetworkChangeListener {fun onNetworkChanged(isConnected: Boolean, type: Int)
}