Android 网络状态获取
网络查询Android 中的网络类型,一般通过以下步骤获取:
使用 ConnectivityManager.getActiveNetworkInfo() 拿到 NetworkInfo。
根据 networkInfo.getType() 判断是 WIFI 或者 移动网络。
如果是移动网络,进一步通过 networkInfo.getSubtype() 判断是 2G、3G、4G、5G 等具体类型。
API 29(Android 10)中,NetworkInfo (包含相关 API)都已被标记为 Deprecated,Google 官方推荐使用 NetworkCapabilities 来判断网络状态。步骤如下:
使用 connectManager.getActiveNetwork() 拿到 Network。
使用 connectManager.getNetworkCapabilities(network) 拿到 NetworkCapabilities。
通过 capabilities.hasCapability() 判断是 WIFI 或者 移动网络。
如果是移动网络,使用 telephonyManager.getDataNetworkType() 判断是 2G、3G、4G、5G 等具体类型。
调用 telephonyManager.getDataNetworkType() 接口 需要用到 READ_PHONE_STATE 敏感权限。
NetworkCapabilities 方法123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354public int GetDetailNetworkState(Context context) { try { if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_NETWORK_STATE)) { Log.w(TAG, "has no ACCESS_NETWORK_STATE permission"); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; } ConnectivityManager connectManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (null == connectManager) { Log.w(TAG, "ConnectivityManager is null"); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; } Network network = connectManager.getActiveNetwork(); NetworkCapabilities capabilities = connectManager.getNetworkCapabilities(network); if (null == capabilities) { Log.w(TAG, "NetworkCapabilities is null"); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; } boolean hasCapability = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); if (!hasCapability) { Log.w(TAG, "has no Capability: NET_CAPABILITY_INTERNET"); return NetworkDefines.NETWORK_STATE_UNAVAILABLE; } boolean hasWifiTrans = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI); if (hasWifiTrans) { return NetworkDefines.NETWORK_STATE_AVAILABLE_WIFI; } boolean hasCellTrans = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); if (hasCellTrans) { if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)) { Log.w(TAG, "has no READ_PHONE_STATE permission"); return NetworkDefines.NETWORK_STATE_AVAILABLE_MOBILE; } TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (null == telephonyManager) { return NetworkDefines.NETWORK_STATE_AVAILABLE_MOBILE; } return covertNetType (telephonyManager.getDataNetworkType()); } return NetworkDefines.NETWORK_STATE_AVAILABLE_OTHER; } catch (Exception e) { Log.w(TAG, "check Get exception:" + e.toString()); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; }}
通过 telephonyManager.getDataNetworkType() 获取移动网络类型,需要用到 READ_PHONE_STATE 权限。
NetworkInfo 方法1234567891011121314151617181920212223242526272829303132333435public int GetDetailNetworkState(Context context) { try { if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_NETWORK_STATE)) { Log.w(TAG, "has no ACCESS_NETWORK_STATE permission"); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; } ConnectivityManager connectManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (null == connectManager) { Log.w(TAG, "ConnectivityManager is null"); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; } NetworkInfo networkInfo = connectManager.getActiveNetworkInfo(); if (null == networkInfo) { Log.w(TAG, "NetworkInfo is null"); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; } if (ConnectivityManager.TYPE_WIFI == networkInfo.getType()) { return NetworkDefines.NETWORK_STATE_AVAILABLE_WIFI; } if (ConnectivityManager.TYPE_MOBILE == networkInfo.getType()) { return covertNetType (networkInfo.getSubtype()); } return NetworkDefines.NETWORK_STATE_AVAILABLE_OTHER; } catch (Exception e) { Log.w(TAG, "check Get exception:" + e.toString()); return NetworkDefines.NETWORK_STATE_AVAILABLE_UNKNOWN; }}
移动网络类型判断1234567891011121314151617181920212223242526272829303132private int covertNetType(int networkType) { switch (networkType) { case TelephonyManager.NETWORK_TYPE_GPRS: case TelephonyManager.NETWORK_TYPE_EDGE: case TelephonyManager.NETWORK_TYPE_CDMA: case TelephonyManager.NETWORK_TYPE_IDEN: case TelephonyManager.NETWORK_TYPE_1xRTT: return NetworkDefines.NETWORK_STATE_AVAILABLE_2G; case TelephonyManager.NETWORK_TYPE_UMTS: case TelephonyManager.NETWORK_TYPE_EVDO_0: case TelephonyManager.NETWORK_TYPE_EVDO_A: case TelephonyManager.NETWORK_TYPE_EVDO_B: case TelephonyManager.NETWORK_TYPE_HSDPA: case TelephonyManager.NETWORK_TYPE_HSUPA: case TelephonyManager.NETWORK_TYPE_HSPA: case TelephonyManager.NETWORK_TYPE_HSPAP: case TelephonyManager.NETWORK_TYPE_EHRPD: return NetworkDefines.NETWORK_STATE_AVAILABLE_3G; case TelephonyManager.NETWORK_TYPE_LTE: case 19: // NETWORK_TYPE_LTE_CA return NetworkDefines.NETWORK_STATE_AVAILABLE_4G; case 20: // NETWORK_TYPE_NR return NetworkDefines.NETWORK_STATE_AVAILABLE_5G; case TelephonyManager.NETWORK_TYPE_UNKNOWN: default: return NetworkDefines.NETWORK_STATE_AVAILABLE_OTHER; }}
网络监听早期的 Android 版本,应用一般采用监听广播的方式,监听系统网络事件。但 Android N 以后,google 官方声明此方法已经不推荐使用。高版本的系统,使用 ConnectivityManager.NetworkCallback 进行网络监听。
无论是广播监听方案,或者是网络回调方案,一般在 onCreate/onDestroy 生命周期中,分别进行注册/反注册监听。
网络回调方案123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960public void registerNetworkListener(Context context) { if (mNetworkChangeCallback != null) { Log.w(TAG, "NetworkCallback registered"); return; } ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivityManager != null) { mNetworkChangeCallback = new NetworkChangeCallback(); connectivityManager.registerDefaultNetworkCallback(mNetworkChangeCallback); }}public void unregisterNetworkListener(Context context) { if (mNetworkChangeCallback != null) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivityManager != null) { connectivityManager.unregisterNetworkCallback(mNetworkChangeCallback); mNetworkChangeCallback = null; } }}@android.support.annotation.RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)protected class NetworkChangeCallback extends ConnectivityManager.NetworkCallback { @Override public void onAvailable(Network network) { super.onAvailable(network); Log.d(TAG, "network available"); handleNetworkChange(NETWORK_STATE_AVAILABLE); } @Override public void onLost(Network network) { super.onLost(network); Log.i(TAG, "network unavailable"); handleNetworkChange(NetworkDefines.NETWORK_STATE_UNAVAILABLE); } @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { super.onCapabilitiesChanged(network, networkCapabilities); if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)){ if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){ Log.i(TAG, "network available for wifi"); handleNetworkChange(NetworkDefines.NETWORK_STATE_AVAILABLE_WIFI); } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { Log.i(TAG, "network available for mobile"); handleNetworkChange(NetworkDefines.NETWORK_STATE_AVAILABLE_MOBILE); } else { Log.i(TAG, "network available for other"); handleNetworkChange(NetworkDefines.NETWORK_STATE_AVAILABLE_OTHER); } } if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { Log.d(TAG, "internet online"); } }}
动态注册广播方案1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556public void registerNetworkListener(Context context) { if (mNetworkChangeReceiver != null) { Log.w(TAG, "NetworkChangeReceiver registered"); return; } mNetworkChangeReceiver = new NetworkChangeReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); context.registerReceiver(mNetworkChangeReceiver, filter);}public void unregisterNetworkListener(Context context) { if (mNetworkChangeReceiver != null) { context.unregisterReceiver(mNetworkChangeReceiver); mNetworkChangeReceiver = null; }}protected class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = connManager.getActiveNetworkInfo(); if(null == netInfo || !netInfo.isConnected()) { handleNetworkChange(NetworkDefines.NETWORK_STATE_UNAVAILABLE); } else { switch (netInfo.getType()) { case ConnectivityManager.TYPE_MOBILE: { Log.i(TAG, "Receive Network State TYPE_MOBILE"); handleNetworkChange(NetworkDefines.NETWORK_STATE_AVAILABLE_MOBILE); break; } case ConnectivityManager.TYPE_WIFI: { Log.i(TAG, "Receive Network State TYPE_WIFI"); handleNetworkChange(NetworkDefines.NETWORK_STATE_AVAILABLE_WIFI); break; } default: { Log.i(TAG, "Receive Network State, Other:" + netInfo.getType()); handleNetworkChange(NetworkDefines.NETWORK_STATE_AVAILABLE_OTHER); break; } } } }}
回调通知处理12345678910111213141516171819202122232425262728293031323334353637383940414243public class NetworkDefines { public static final int NETWORK_STATE_AVAILABLE_UNKNOWN= -1; public static final int NETWORK_STATE_UNAVAILABLE = 0; public static final int NETWORK_STATE_AVAILABLE_MOBILE = 1; public static final int NETWORK_STATE_AVAILABLE_WIFI = 2; public static final int NETWORK_STATE_AVAILABLE_OTHER = 3; public static final int NETWORK_STATE_AVAILABLE_2G = 12; public static final int NETWORK_STATE_AVAILABLE_3G = 13; public static final int NETWORK_STATE_AVAILABLE_4G = 14; public static final int NETWORK_STATE_AVAILABLE_5G = 15;}private void handleNetworkChange(int networkState) { if (mLastState == networkState) { Log.w(TAG, "Network State not change:" + networkState); return; } if (mLastState != NetworkDefines.NETWORK_STATE_UNAVAILABLE && networkState != NetworkDefines.NETWORK_STATE_UNAVAILABLE) { // insert NotReachable state Log.i(TAG,"Notify: Network State change to TYPE_NONE (insert)"); } mLastState = networkState; switch (networkState){ case NetworkDefines.NETWORK_STATE_UNAVAILABLE: Log.i(TAG,"Notify: Network State change to TYPE_NONE"); break; case NetworkDefines.NETWORK_STATE_AVAILABLE_WIFI: Log.i(TAG,"Notify: Network State change to TYPE_WIFI"); break; case NetworkDefines.NETWORK_STATE_AVAILABLE_MOBILE: Log.i(TAG,"Notify: Network State change to TYPE_MOBILE"); break; case NetworkDefines.NETWORK_STATE_AVAILABLE_OTHER: Log.i(TAG,"Notify: Network State change to TYPE_OTHER"); break; default: break; }}
正常来说,任何两个网络直接切换,都会产生一个断网的中间状态,但是某些情况下,监听结果会直接跳过。为了保证一致性,在回调处理时,会根据前一次的状态,插入一个断网态。
参考文档