网络查询

Android 中的网络类型,一般通过以下步骤获取:

  1. 使用 ConnectivityManager.getActiveNetworkInfo() 拿到 NetworkInfo。
  2. 根据 networkInfo.getType() 判断是 WIFI 或者 移动网络。
  3. 如果是移动网络,进一步通过 networkInfo.getSubtype() 判断是 2G、3G、4G、5G 等具体类型。

API 29(Android 10)中,NetworkInfo (包含相关 API)都已被标记为 Deprecated,Google 官方推荐使用 NetworkCapabilities 来判断网络状态。步骤如下:

  1. 使用 connectManager.getActiveNetwork() 拿到 Network。
  2. 使用 connectManager.getNetworkCapabilities(network) 拿到 NetworkCapabilities。
  3. 通过 capabilities.hasCapability() 判断是 WIFI 或者 移动网络。
  4. 如果是移动网络,使用 telephonyManager.getDataNetworkType() 判断是 2G、3G、4G、5G 等具体类型。

调用 telephonyManager.getDataNetworkType() 接口 需要用到 READ_PHONE_STATE 敏感权限。

NetworkCapabilities 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public 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 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public 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;
}
}

移动网络类型判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private 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 生命周期中,分别进行注册/反注册监听。

网络回调方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public 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");
}
}
}

动态注册广播方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

public 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;
}
}
}
}
}

回调通知处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public 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;
}
}

正常来说,任何两个网络直接切换,都会产生一个断网的中间状态,但是某些情况下,监听结果会直接跳过。为了保证一致性,在回调处理时,会根据前一次的状态,插入一个断网态。

参考文档