本文将介绍如何在Android应用中实现全局网络状态监控,适配高版本API,并提供完整的Kotlin实现方案。
一、核心实现方案
1. 网络监控核心类
@SuppressLint("MissingPermission")
class NetworkMonitor private constructor(private val context: Context) {
// 网络状态变化回调
sealed interface NetworkStatus {
object Available : NetworkStatus
object Lost : NetworkStatus
data class Changed(val type: NetworkType) : NetworkStatus
}
private val connectivityManager by lazy {
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
private val _networkStatus = MutableSharedFlow<NetworkStatus>()
val networkStatus = _networkStatus.asSharedFlow()
private val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
postStatus(NetworkStatus.Available)
}
override fun onLost(network: Network) {
postStatus(NetworkStatus.Lost)
}
override fun onCapabilitiesChanged(
network: Network,
capabilities: NetworkCapabilities
) {
val type = when {
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ->
NetworkType.WIFI
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ->
NetworkType.CELLULAR
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ->
NetworkType.ETHERNET
else -> NetworkType.UNKNOWN
}
postStatus(NetworkStatus.Changed(type))
}
}
fun register() {
val request = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build()
connectivityManager.registerNetworkCallback(request, callback)
}
fun unregister() {
try {
connectivityManager.unregisterNetworkCallback(callback)
} catch (e: IllegalArgumentException) {
// 忽略未注册的异常
}
}
private fun postStatus(status: NetworkStatus) {
MainScope().launch {
_networkStatus.emit(status)
}
}
companion object {
@Volatile
private var instance: NetworkMonitor? = null
fun getInstance(context: Context): NetworkMonitor =
instance ?: synchronized(this) {
instance ?: NetworkMonitor(context.applicationContext).also { instance = it }
}
}
}
enum class NetworkType {
WIFI, CELLULAR, ETHERNET, UNKNOWN
}
2. Application初始化
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
NetworkMonitor.getInstance(this).register()
}
}
在AndroidManifest.xml中注册:
<application
android:name=".MyApp"
...>
</application>
二、使用示例
1. Activity/Fragment中使用
class MainActivity : AppCompatActivity() {
private var networkJob: Job? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
observeNetworkStatus()
}
private fun observeNetworkStatus() {
networkJob = lifecycleScope.launch {
NetworkMonitor.getInstance(this@MainActivity)
.networkStatus
.collect { status ->
when (status) {
is NetworkMonitor.NetworkStatus.Available -> {
showNetworkConnected()
}
is NetworkMonitor.NetworkStatus.Lost -> {
showNetworkDisconnected()
}
is NetworkMonitor.NetworkStatus.Changed -> {
updateNetworkType(status.type)
}
}
}
}
}
private fun showNetworkConnected() {
Toast.makeText(this, "网络已连接", Toast.LENGTH_SHORT).show()
binding.networkStatusIndicator.setBackgroundColor(Color.GREEN)
}
private fun showNetworkDisconnected() {
Toast.makeText(this, "网络已断开", Toast.LENGTH_SHORT).show()
binding.networkStatusIndicator.setBackgroundColor(Color.RED)
}
private fun updateNetworkType(type: NetworkType) {
val typeText = when (type) {
NetworkType.WIFI -> "WiFi网络"
NetworkType.CELLULAR -> "移动网络"
NetworkType.ETHERNET -> "有线网络"
NetworkType.UNKNOWN -> "未知网络"
}
binding.networkTypeText.text = "当前网络: $typeText"
}
override fun onDestroy() {
super.onDestroy()
networkJob?.cancel()
}
}
2. ViewModel中使用
class MyViewModel(application: Application) : AndroidViewModel(application) {
private val monitor = NetworkMonitor.getInstance(application)
val networkStatus = monitor.networkStatus
.stateIn(
viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = NetworkMonitor.NetworkStatus.Available
)
}
三、兼容性处理
1. 权限声明
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2. 低版本兼容检查
fun checkNetworkAvailable(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val activeNetwork = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true &&
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
} else {
@Suppress("DEPRECATION")
connectivityManager.activeNetworkInfo?.isConnected == true
}
}
四、高级功能扩展
1. 检测网络质量
fun getNetworkQuality(): NetworkQuality {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val activeNetwork = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
return when {
capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) == false ->
NetworkQuality.ROAMING
capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) == false ->
NetworkQuality.METERED
capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) == false ->
NetworkQuality.CONGESTED
else -> NetworkQuality.GOOD
}
}
return NetworkQuality.UNKNOWN
}
enum class NetworkQuality {
GOOD, METERED, ROAMING, CONGESTED, UNKNOWN
}
2. 监听特定网络状态
fun observeWifiStatus(): Flow<Boolean> = networkStatus
.map { status ->
when (status) {
is NetworkStatus.Changed -> status.type == NetworkType.WIFI
else -> false
}
}
.distinctUntilChanged()
五、最佳实践建议
- 生命周期管理:确保在适当的生命周期注册和注销监听
- 错误处理:添加适当的异常处理
- 线程安全:确保网络状态更新在主线程执行UI操作
- 性能优化:避免频繁的网络状态检查
- 用户体验:提供友好的网络状态提示
六、总结
本文介绍了Android全局网络监控的完整实现方案,具有以下特点:
- 使用现代Android API(NetworkCallback)
- 支持响应式编程(Flow)
- 提供详细的网络状态信息
- 良好的兼容性处理
- 易于扩展的高级功能
这种实现方式适用于大多数现代Android应用,能够有效监控网络状态变化,为用户提供更好的网络体验。