睿诚科技协会

Android如何实时检测网络状态变化?

核心概念

无论使用哪种 API,核心都是通过 ConnectivityManager 这个系统服务来获取网络信息。

Android如何实时检测网络状态变化?-图1
(图片来源网络,侵删)

使用 BroadcastReceiver (传统方式,适用于旧版 API)

这是最传统的方法,通过监听系统广播来获知网络状态的变化,优点是简单直接,缺点是注册广播和解绑的代码比较繁琐,并且从 Android 8.0 (Oreo) 开始,对隐式广播的接收有严格限制,不推荐在新应用中使用

添加网络权限

AndroidManifest.xml 中必须声明以下权限:

<!-- 允许应用访问网络状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 如果需要检测 Wi-Fi 状态,还需要此权限 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

创建 BroadcastReceiver

创建一个继承自 BroadcastReceiver 的类,并重写 onReceive 方法。

public class NetworkChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 检查是否是网络状态变化的广播
        if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
                // 网络已连接
                Log.d("NetworkChange", "网络已连接: " + activeNetworkInfo.getTypeName());
            } else {
                // 网络已断开
                Log.d("NetworkChange", "网络已断开");
            }
        }
    }
}

在 AndroidManifest.xml 中注册广播

<receiver android:name=".NetworkChangeReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

在 Activity 中动态注册 (可选)

为了避免清单注册的限制,也可以在 Activity 中动态注册和解绑。

Android如何实时检测网络状态变化?-图2
(图片来源网络,侵删)
// 在 Activity 的 onCreate 中注册
registerReceiver(networkChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_CHANGE));
// 在 Activity 的 onDestroy 中解绑
unregisterReceiver(networkChangeReceiver);

使用 ConnectivityManager.NetworkCallback (推荐方式,API 21+)

这是目前最推荐的方式,它不需要使用广播,而是通过回调的方式监听网络状态的变化,更加高效和现代化。

添加网络权限

与方法一相同,需要在 AndroidManifest.xml 中添加 ACCESS_NETWORK_STATE 权限。

实现 NetworkCallback

创建一个 ConnectivityManager.NetworkCallback 的子类,并重写你关心的回调方法。

public class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {
    @Override
    public void onAvailable(Network network) {
        // 网络可用时调用
        Log.d("NetworkCallback", "网络已连接");
    }
    @Override
    public void onLost(Network network) {
        // 网络丢失时调用
        Log.d("NetworkCallback", "网络已断开");
    }
    @Override
    public void onUnavailable() {
        // 没有任何可用的网络时调用
        Log.d("NetworkCallback", "网络不可用");
    }
}

在 Activity/Service 中注册和注销回调

private ConnectivityManager.NetworkCallback networkCallback;
private ConnectivityManager connectivityManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    networkCallback = new NetworkCallbackImpl();
    // 创建网络请求
    NetworkRequest networkRequest = new NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) // 要求有互联网能力
            .build();
    // 注册网络回调
    connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
}
@Override
protected void onDestroy() {
    super.onDestroy();
    // 务必在不需要时注销回调,否则会内存泄漏
    if (connectivityManager != null && networkCallback != null) {
        connectivityManager.unregisterNetworkCallback(networkCallback);
    }
}

使用 Kotlin Flow (现代方式,Kotlin + Coroutines)

如果你使用 Kotlin 并且项目使用了 Coroutines,可以结合 NetworkCallback 封装成一个 Flow,这样可以在 ViewModel 或其他地方更优雅地响应网络状态。

Android如何实时检测网络状态变化?-图3
(图片来源网络,侵删)

添加依赖

确保你的项目已经添加了 Coroutines 依赖。

// build.gradle (Module: app)
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'

创建 NetworkStatus 枚举

enum class NetworkStatus {
    Available, Unavailable, Lost
}

封装 NetworkCallback 为 Flow

// NetworkCallback.kt
object NetworkCallbackFlow {
    fun observeNetworkStatus(context: Context): Flow<NetworkStatus> = callbackFlow {
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val callback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                trySend(NetworkStatus.Available)
            }
            override fun onLost(network: Network) {
                trySend(NetworkStatus.Lost)
            }
            override fun onUnavailable() {
                trySend(NetworkStatus.Unavailable)
            }
        }
        val networkRequest = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build()
        connectivityManager.registerNetworkCallback(networkRequest, callback)
        // 设置通道关闭时的清理逻辑
        awaitClose {
            connectivityManager.unregisterNetworkCallback(callback)
        }
    }
}

在 ViewModel 或 Activity 中使用

// 在 ViewModel 中使用
class MainViewModel : ViewModel() {
    private val _networkStatus = MutableStateFlow<NetworkStatus?>(null)
    val networkStatus: StateFlow<NetworkStatus?> = _networkStatus
    init {
        viewModelScope.launch {
            NetworkCallbackFlow.observeNetworkStatus(getApplication())
                .collect { status ->
                    _networkStatus.value = status
                    // 在这里处理网络状态变化
                    when (status) {
                        NetworkStatus.Available -> Log.d("ViewModel", "网络已连接")
                        NetworkStatus.Lost -> Log.d("ViewModel", "网络已断开")
                        NetworkStatus.Unavailable -> Log.d("ViewModel", "网络不可用")
                    }
                }
        }
    }
}

使用 Jetpack Compose (最新方式)

如果你的 UI 是用 Jetpack Compose 实现的,官方提供了 ConnectivityStatusConnectivityMonitor 等工具来简化网络状态的获取。

添加依赖

// build.gradle (Module: app)
implementation "androidx.compose.material3:material3:1.1.2" // 或其他版本
implementation "com.google.accompanist:accompanist-permissions:0.32.0" // 包含网络状态监测

(注意:Accompanist 项目已归档,其功能正被官方库取代,具体请查看最新文档)

在 Composable 中使用

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun NetworkStatusScreen(viewModel: MainViewModel = viewModel()) {
    val networkStatus by viewModel.networkStatus.collectAsState()
    Text(
        text = when (networkStatus) {
            NetworkStatus.Available -> "网络已连接"
            NetworkStatus.Lost -> "网络已断开"
            NetworkStatus.Unavailable -> "网络不可用"
            null -> "正在检测网络..."
        }
    )
}

这里的 MainViewModel 就是上面用 Kotlin Flow 封装的那个。


方法 优点 缺点 推荐场景
BroadcastReceiver 简单,兼容性好 效率低,代码繁琐,Android 8.0+ 受限 维护旧项目 (API < 21)
NetworkCallback 推荐,高效,非阻塞,现代化 需要 API 21+ 所有新项目,Java/Kotlin 均可
Kotlin Flow 优雅,响应式,易于在 ViewModel 中使用 仅限 Kotlin,需要 Coroutines 知识 Kotlin 项目,MVVM 架构
Jetpack Compose 与 Compose UI 深度集成,声明式 仅限 Compose 项目 使用 Compose 的项目

对于任何新项目,强烈推荐使用 ConnectivityManager.NetworkCallback,如果你使用 Kotlin 并且项目采用了 MVVM 架构,那么将 NetworkCallback 封装成 Kotlin Flow 是最佳选择,因为它能让你的代码更简洁、更具响应式特性,对于纯 Compose 项目,则应使用 Compose 提供的相关工具。

分享:
扫描分享到社交APP
上一篇
下一篇