睿诚科技协会

Android如何准确获取当前网络状态?

核心概念

在开始之前,需要理解几个核心概念:

Android如何准确获取当前网络状态?-图1
(图片来源网络,侵删)
  1. 网络连接类型

    • ConnectivityManager: 这是 Android 系统中管理所有网络连接的核心类,通过它可以查询可用的网络、网络状态等。
    • NetworkCapabilities: 这是 Android 7.0 (API 24) 引入的新概念,用来描述一个网络的能力,比如是否有互联网连接、是否是漫游、是否是_metered(按流量计费)等。
    • NetworkInfo: 这是旧版本使用的类,用于描述网络信息,如类型(移动、Wi-Fi)、状态(连接中、已连接、断开等)。在 Android 10 (API 29) 中已被废弃
  2. 网络权限

    • 要访问网络状态,必须在 AndroidManifest.xml 中声明网络权限。
    • 对于现代 Android 版本(API 28+),建议使用 ACCESS_NETWORK_STATE 权限,它比 INTERNET 权限更精确,只允许应用查询网络状态,而不是访问网络。

使用 ConnectivityManager (推荐,适用于所有版本)

这是最主流和官方推荐的方法,我们将根据 Android 版本的不同,展示如何使用它。

第 1 步:添加权限

app/src/main/AndroidManifest.xml 文件中添加以下权限:

Android如何准确获取当前网络状态?-图2
(图片来源网络,侵删)
<!-- 允许应用访问网络状态信息 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 如果你的应用需要连接网络,还需要这个权限 -->
<uses-permission android:name="android.permission.INTERNET" />

第 2 步:编写代码

检查是否有网络连接 (通用方法)

这个方法可以检查设备是否连接到了某个网络,但不一定是可用的互联网。

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class NetworkUtils {
    /**
     * 检查是否有任何网络连接
     * @param context 上下文
     * @return true 表示有网络连接,false 表示没有
     */
    public static boolean isNetworkConnected(Context context) {
        if (context != null) {
            ConnectivityManager connectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            // 在旧版本中,使用 getActiveNetworkInfo()
            NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            if (activeNetworkInfo != null) {
                return activeNetworkInfo.isConnected();
            }
        }
        return false;
    }
}

检查是否有可用的互联网连接 (推荐)

仅仅连接到网络不代表可以上网(连接到了一个没有外网的 Wi-Fi),更可靠的方法是检查网络是否具有 INTERNET 能力。

对于 Android 7.0 (API 24) 及以上版本:

这是现代 Android 开发的首选方式。

Android如何准确获取当前网络状态?-图3
(图片来源网络,侵删)
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import androidx.annotation.NonNull;
public class NetworkUtils {
    /**
     * 检查是否有可用的互联网连接 (API 24+)
     * @param context 上下文
     * @return true 表示有可用的互联网连接,false 表示没有
     */
    public static boolean isInternetAvailable(Context context) {
        if (context == null) {
            return false;
        }
        ConnectivityManager connectivityManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        // 在 Android 10 (API 29) 及以上,getActiveNetwork() 是推荐方法
        Network network = connectivityManager.getActiveNetwork();
        if (network == null) {
            return false;
        }
        // 获取网络的能力
        NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
        if (capabilities == null) {
            return false;
        }
        // 检查网络是否具备互联网连接能力
        return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
               capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
    }
}

对于 Android 6.0 (API 23) 及以下版本:

如果需要兼容旧版本,可以结合使用 NetworkInfoNetworkCapabilities 的方式。

// 在同一个 NetworkUtils 类中添加这个方法
public static boolean isInternetAvailableLegacy(Context context) {
    if (context == null) {
        return false;
    }
    ConnectivityManager connectivityManager = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    // 1. 首先尝试使用新方法 (API 23+)
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        Network network = connectivityManager.getActiveNetwork();
        if (network != null) {
            NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
            if (capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
                return true;
            }
        }
    }
    // 2. 如果新方法不可用,则回退到旧方法 (API 23-)
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected() && activeNetworkInfo.isAvailable();
}

获取具体的网络类型 (Wi-Fi, 移动数据等)

对于 Android 7.0 (API 24) 及以上版本:

public static String getNetworkType(Context context) {
    if (context == null) {
        return "Unknown";
    }
    ConnectivityManager connectivityManager = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    Network network = connectivityManager.getActiveNetwork();
    if (network == null) {
        return "No Network";
    }
    NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
    if (capabilities == null) {
        return "Unknown";
    }
    if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
        return "Wi-Fi";
    } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
        return "Mobile";
    } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
        return "Ethernet";
    } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
        return "Bluetooth";
    }
    return "Unknown";
}

对于 Android 6.0 (API 23) 及以下版本:

// 在同一个 NetworkUtils 类中添加这个方法
public static String getNetworkTypeLegacy(Context context) {
    if (context == null) {
        return "Unknown";
    }
    ConnectivityManager connectivityManager = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    if (activeNetworkInfo == null || !activeNetworkInfo.isConnected()) {
        return "No Network";
    }
    int type = activeNetworkInfo.getType();
    switch (type) {
        case ConnectivityManager.TYPE_WIFI:
            return "Wi-Fi";
        case ConnectivityManager.TYPE_MOBILE:
            return "Mobile";
        case ConnectivityManager.TYPE_ETHERNET:
            return "Ethernet";
        default:
            return "Unknown";
    }
}

监听网络状态变化

很多时候,你需要在网络状态改变时(从 Wi-Fi 切换到移动数据)执行一些操作,比如刷新数据,这时就需要使用 NetworkCallback

注册网络监听器

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Build;
public class NetworkMonitor {
    private ConnectivityManager.NetworkCallback networkCallback;
    private ConnectivityManager connectivityManager;
    public void register(Context context) {
        connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkRequest.Builder builder = new NetworkRequest.Builder();
        // 设置监听的网络能力
        builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
        builder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // 对于 Android 7.0+,可以指定网络类型
            builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
            // builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
        }
        NetworkRequest networkRequest = builder.build();
        // 创建回调
        networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(@NonNull Network network) {
                // 网络变为可用时调用
                Log.d("NetworkMonitor", "Network is available!");
                // 在这里执行网络恢复后的操作,比如重新加载数据
            }
            @Override
            public void onLost(@NonNull Network network) {
                // 网络丢失时调用
                Log.d("NetworkMonitor", "Network is lost!");
                // 在这里执行网络丢失后的操作,比如停止下载
            }
            @Override
            public void onUnavailable() {
                // 没有任何可用网络时调用
                Log.d("NetworkMonitor", "No available network!");
            }
        };
        // 注册回调
        connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
    }
    public void unregister() {
        if (connectivityManager != null && networkCallback != null) {
            connectivityManager.unregisterNetworkCallback(networkCallback);
            networkCallback = null;
        }
    }
}

在 Activity/Service 中使用

public class MainActivity extends AppCompatActivity {
    private NetworkMonitor networkMonitor;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        networkMonitor = new NetworkMonitor();
    }
    @Override
    protected void onStart() {
        super.onStart();
        // 在 Activity 可见时开始监听
        networkMonitor.register(this);
    }
    @Override
    protected void onStop() {
        super.onStop();
        // 在 Activity 不可见时停止监听,防止内存泄漏
        networkMonitor.unregister();
    }
}

总结与最佳实践

  1. 权限是基础:别忘了在 AndroidManifest.xml 中声明 ACCESS_NETWORK_STATE 权限。
  2. 版本适配是关键
    • 目标 API 29+:应完全使用 ConnectivityManager.getActiveNetwork()NetworkCapabilities
    • 需要兼容旧版:使用 Build.VERSION.SDK_INT 进行判断,优先使用新 API,失败后回退到 NetworkInfo
  3. 功能区分
    • 想知道 是否连接到网络,用 isNetworkConnected
    • 想知道 是否能上网,用 isInternetAvailable,这是更可靠的方式。
    • 想知道 网络的具体类型,用 getNetworkType
    • 想在 网络变化时响应,用 NetworkCallback
  4. 生命周期管理NetworkCallback 的注册和注销要与组件的生命周期(如 ActivityonStart/onStop)绑定,避免内存泄漏和不必要的资源消耗。

希望这份详细的指南能帮助你完美地在 Android 应用中处理网络状态!

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