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

核心思路
判断 4G 网络主要分为两步:
- 获取当前活动的网络连接:使用
ConnectivityManager检查设备是否有活动的网络连接,并且该连接的类型是移动数据(ConnectivityManager.TYPE_MOBILE)。 - 获取移动网络的具体类型:如果第一步满足,再使用
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),我们会将LTE和NR都视为高速移动网络,4G 仅指LTE。 - 兼容性处理:为了覆盖所有设备,特别是那些可能未正确实现新 API 的旧设备,我们需要一个兼容的判断方法。
- 旧版 (API < 28):使用
完整代码示例
这是一个完整的、考虑了向后兼容的工具类 NetworkUtils,你可以直接复制到你的项目中使用。
添加网络权限
在 AndroidManifest.xml 中必须声明以下权限:

<!-- 用于获取网络状态信息 --> <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));
}
}
重要注意事项
-
Android 10 (API 29) 的变化:
- 从 Android 10 开始,
READ_PHONE_STATE权限不再允许访问详细的网络类型信息(如getDataNetworkType())。必须依赖ACCESS_NETWORK_STATE权限 和ConnectivityManager的新 API(getActiveNetwork()和getNetworkCapabilities())来获取网络信息。 - 上述代码已经处理了这一点,是兼容 Android 10+ 的正确方式。
- 从 Android 10 开始,
-
后台限制:
- 在后台(Service 或 BroadcastReceiver)中,
getActiveNetwork()和getNetworkCapabilities()的行为可能会受到系统省电策略的限制,返回的结果可能不准确,对于需要实时监听网络变化的场景,推荐使用ConnectivityManager.NetworkCallback,并在前台注册。
- 在后台(Service 或 BroadcastReceiver)中,
-
多 SIM 卡设备:
(图片来源网络,侵删)- 上述代码获取的是默认数据卡的网络状态,如果你的应用需要处理多张 SIM 卡的情况,需要使用
TelephonyManager的getSubscriberCount()等方法来遍历所有可用的订阅者(Subscription),并分别检查它们的网络类型,这会使逻辑更复杂。
- 上述代码获取的是默认数据卡的网络状态,如果你的应用需要处理多张 SIM 卡的情况,需要使用
-
网络类型的不确定性:
- 在信号切换时(从 4G 切换到 3G),获取网络类型可能会有短暂的延迟或返回不正确的值,对于需要高精度判断的场景,最好结合多次检查或使用
NetworkCallback来监听变化。
- 在信号切换时(从 4G 切换到 3G),获取网络类型可能会有短暂的延迟或返回不正确的值,对于需要高精度判断的场景,最好结合多次检查或使用
其他判断方式(不推荐,但需了解)
旧版方式(仅适用于 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 中注册,在 onPause 或 onDestroy 中注销,以避免内存泄漏。
