睿诚科技协会

android 4g网络判断

下面我将从 核心思路完整代码示例注意事项其他判断方式 四个方面进行详细说明。

android 4g网络判断-图1
(图片来源网络,侵删)

核心思路

判断 4G 网络主要分为两步:

  1. 获取当前活动的网络连接:使用 ConnectivityManager 检查设备是否有活动的网络连接,并且该连接的类型是移动数据(ConnectivityManager.TYPE_MOBILE)。
  2. 获取移动网络的具体类型:如果第一步满足,再使用 TelephonyManager 获取当前移动网络的技术类型(如 2G, 3G, 4G, 5G),并判断它是否为 4G。

关键点:

  • 网络类型常量:不同 Android 版本对 4G 的定义和 API 不同。
    • 旧版 (API < 28):使用 TelephonyManager.NETWORK_TYPE_LTE,LTE 是 4G 的技术标准。
    • 新版 (API >= 28):引入了 TelephonyManager.NETWORK_TYPE_LTE,但为了更精确,还增加了 NETWORK_TYPE_NR(5G Standalone)和 NETWORK_TYPE_NSA(5G Non-Standalone),我们会将 LTENR 都视为高速移动网络,4G 仅指 LTE
    • 兼容性处理:为了覆盖所有设备,特别是那些可能未正确实现新 API 的旧设备,我们需要一个兼容的判断方法。

完整代码示例

这是一个完整的、考虑了向后兼容的工具类 NetworkUtils,你可以直接复制到你的项目中使用。

添加网络权限

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

android 4g网络判断-图2
(图片来源网络,侵删)
<!-- 用于获取网络状态信息 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 用于获取网络状态信息 (Android 10+ 需要显式声明) -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 虽然判断4G,但这是网络权限组的一部分 -->
<!-- 如果你的App需要主动请求网络状态变化,还需要此权限 (Android 6.0+ 运行时权限) -->
<!-- <uses-permission android:name="android.permission.READ_PHONE_STATE" /> -->
<!-- 注意:从 Android 10 (API 29) 开始,READ_PHONE_STATE 权限的范围被收紧,仅对设备标识符和通话状态有效,不再提供详细的网络信息,对于新版本,我们主要依赖 ACCESS_NETWORK_STATE。 -->

NetworkUtils 工具类

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.TelephonyManager;
import androidx.annotation.RequiresApi;
public class NetworkUtils {
    /**
     * 检查当前网络是否是4G
     *
     * @param context 上下文
     * @return true 如果当前是4G网络,否则 false
     */
    public static boolean is4GConnected(Context context) {
        // 1. 首先检查是否有活动的网络连接
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager == null) {
            return false;
        }
        // 2. 检查网络连接是否可用
        Network activeNetwork = connectivityManager.getActiveNetwork();
        if (activeNetwork == null) {
            return false;
        }
        // 3. 获取网络能力
        NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(activeNetwork);
        if (capabilities == null) {
            return false;
        }
        // 4. 检查是否是移动数据网络
        if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
            return false;
        }
        // 5. 检查网络是否已连接
        if (!capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ||
                !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
            return false;
        }
        // 6. 获取具体的网络类型 (这是最关键的一步)
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (telephonyManager == null) {
            return false;
        }
        int networkType = telephonyManager.getDataNetworkType();
        // 7. 根据API版本判断
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // API 29+
            // 在 Android 10 及以上,NetworkCapabilities 已经能提供很多信息
            // 但为了精确判断4G,我们仍然需要 TelephonyManager
            // LTE 是 4G, NR 是 5G
            return networkType == TelephonyManager.NETWORK_TYPE_LTE;
        } else { // API < 29
            // 在旧版本上,直接判断 LTE
            return networkType == TelephonyManager.NETWORK_TYPE_LTE;
        }
    }
    /**
     * (可选) 一个更全面的网络类型判断方法,可以判断2G, 3G, 4G, 5G
     * @param context 上下文
     * @return 网络类型字符串
     */
    @SuppressLint("DefaultLocale")
    public static String getNetworkTypeString(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager == null) {
            return "Unknown";
        }
        Network activeNetwork = connectivityManager.getActiveNetwork();
        if (activeNetwork == null) {
            return "No Network";
        }
        NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(activeNetwork);
        if (capabilities == null || !capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
            return "Not Cellular";
        }
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (telephonyManager == null) {
            return "Unknown";
        }
        int networkType = telephonyManager.getDataNetworkType();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (networkType == TelephonyManager.NETWORK_TYPE_NR) {
                return "5G (NR)";
            }
        }
        if (networkType == TelephonyManager.NETWORK_TYPE_LTE) {
            return "4G (LTE)";
        }
        // 以下是3G及以下类型,判断逻辑较复杂,这里只列出常见的
        if (networkType == TelephonyManager.NETWORK_TYPE_HSPAP ||
                networkType == TelephonyManager.NETWORK_TYPE_HSUPA ||
                networkType == TelephonyManager.NETWORK_TYPE_HSDPA) {
            return "3G (HSPA)";
        }
        if (networkType == TelephonyManager.NETWORK_TYPE_EVDO_0 ||
            networkType == TelephonyManager.NETWORK_TYPE_EVDO_A ||
            networkType == TelephonyManager.NETWORK_TYPE_EVDO_B) {
            return "3G (CDMA EVDO)";
        }
        if (networkType == TelephonyManager.NETWORK_TYPE_EDGE ||
            networkType == TelephonyManager.NETWORK_TYPE_GPRS ||
            networkType == TelephonyManager.NETWORK_TYPE_CDMA) {
            return "2G";
        }
        return String.format("Unknown (%d)", networkType);
    }
}

如何使用

在你的 Activity 或其他地方调用即可:

// 在 Activity 中使用
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (NetworkUtils.is4GConnected(this)) {
        Toast.makeText(this, "当前是4G网络", Toast.LENGTH_SHORT).show();
        Log.d("NetworkCheck", "Current network is 4G");
    } else {
        Toast.makeText(this, "当前不是4G网络", Toast.LENGTH_SHORT).show();
        Log.d("NetworkCheck", "Current network is NOT 4G. Type: " + NetworkUtils.getNetworkTypeString(this));
    }
}

重要注意事项

  1. Android 10 (API 29) 的变化

    • 从 Android 10 开始,READ_PHONE_STATE 权限不再允许访问详细的网络类型信息(如 getDataNetworkType())。必须依赖 ACCESS_NETWORK_STATE 权限ConnectivityManager 的新 API(getActiveNetwork()getNetworkCapabilities())来获取网络信息。
    • 上述代码已经处理了这一点,是兼容 Android 10+ 的正确方式。
  2. 后台限制

    • 在后台(Service 或 BroadcastReceiver)中,getActiveNetwork()getNetworkCapabilities() 的行为可能会受到系统省电策略的限制,返回的结果可能不准确,对于需要实时监听网络变化的场景,推荐使用 ConnectivityManager.NetworkCallback,并在前台注册。
  3. 多 SIM 卡设备

    android 4g网络判断-图3
    (图片来源网络,侵删)
    • 上述代码获取的是默认数据卡的网络状态,如果你的应用需要处理多张 SIM 卡的情况,需要使用 TelephonyManagergetSubscriberCount() 等方法来遍历所有可用的订阅者(Subscription),并分别检查它们的网络类型,这会使逻辑更复杂。
  4. 网络类型的不确定性

    • 在信号切换时(从 4G 切换到 3G),获取网络类型可能会有短暂的延迟或返回不正确的值,对于需要高精度判断的场景,最好结合多次检查或使用 NetworkCallback 来监听变化。

其他判断方式(不推荐,但需了解)

旧版方式(仅适用于 API < 23)

在 Android 6.0 (API 23) 之前,可以使用以下方式,但现在已经过时且不安全:

// 过时的方法,不要在新代码中使用
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
private boolean is4G_OldWay(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (activeNetwork != null && activeNetwork.isConnectedOrConnecting()) {
        if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
            int networkType = activeNetwork.getSubtype();
            return networkType == TelephonyManager.NETWORK_TYPE_LTE;
        }
    }
    return false;
}

缺点getSubtype() 在 Android 6.0 之后已被废弃,且 getActiveNetworkInfo() 在 Android 10+ 后台限制下行为不可靠。

使用 NetworkCallback(推荐用于监听网络变化)

如果你需要实时响应网络类型的变化(从 4G 切换到 Wi-Fi),使用 NetworkCallback 是最佳选择。

private ConnectivityManager.NetworkCallback networkCallback;
public void registerNetworkCallback(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager == null) return;
    NetworkRequest request = new NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .build();
    networkCallback = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(Network network) {
            // 网络可用时,可以在这里再次调用 is4GConnected 进行判断
            Log.d("NetworkCallback", "Cellular network available.");
            if (NetworkUtils.is4GConnected(context)) {
                Log.d("NetworkCallback", "Network is 4G.");
            }
        }
        @Override
        public void onLost(Network network) {
            Log.d("NetworkCallback", "Cellular network lost.");
        }
    };
    connectivityManager.registerNetworkCallback(request, networkCallback);
}
public void unregisterNetworkCallback(Context context) {
    if (networkCallback != null) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager != null) {
            connectivityManager.unregisterNetworkCallback(networkCallback);
        }
        networkCallback = null;
    }
}

注意:在 Activity/Fragment 的 onResume 中注册,在 onPauseonDestroy 中注销,以避免内存泄漏。

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