android7.0开始,无法通过在清单文件中注册广播接收器来监听CONNECTIVITY_ACTION广播。很多app都会监听网络变化,单次网络变化,所有静态监听该广播的应用都会被唤起并同时处理它。特别是那些根本没有启动进程的app,也不得不被唤起处理它,十分浪费性能。通过Context.registerReceiver()动态注册的广播依然可以收到CONNECTIVITY_ACTION广播,但不推荐那么做。
android推荐我们通过ConnectivityManager.registerNetworkCallback()方式注册网络变化监听器。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//获取ConnectivityManager
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
//创建NetworkRequest对象,定制化监听
NetworkRequest customMonitor = new NetworkRequest.Builder().build();
//创建网路变化监听器
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
//当网络连接可用时回调
@Override
public void onAvailable(@NonNull Network network) {
super.onAvailable(network);
EasyLogger.d("on network connected");
}
//当网络断开时回调
@Override
public void onLost(@NonNull Network network) {
super.onLost(network);
EasyLogger.d("on network disconnected");
}
//当网络属性变化时回调
@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
boolean isMobileNetwork = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
boolean isWifiNetwork = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
boolean notUseVPN = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
EasyLogger.d("is mobile network:" + isMobileNetwork + ";is wifi network:" + isWifiNetwork + "; use :" + !notUseVPN);
}
};
//注册网络监听器
connectivityManager.registerNetworkCallback(customMonitor, networkCallback);
}
该API自5.0开始引入,建议5.0及以上版本均采用该方式监听网络变化。既然意识到这个性能问题,能够在更低的版本进行优化自然是好事。
先看第一个参数,NetworkRequest用来定制化监听,只有符合约束条件的网络变化才会回调NetworkCallback中的方法。
new NetworkRequest.Builder()
//移动网络
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
addTransportType()用来添加网络类型约束,上面的代码表示只监听移动网络。多个TransportType之间是“或”的关系,即满足其中之一即可。
new NetworkRequest.Builder()
//移动网络
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
//wifi网络
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
上面的代码表示监听移动网络或wifi网络。
removeTransportType()可以删除某个约束,假如它存在的话。
new NetworkRequest.Builder()
//如果存在wifi网络约束,则删除
.removeTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
new NetworkRequest.Builder()
//没有使用
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
//非漫游网络
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
.build();
addCapability()用来添加一些网络属性,比如没有使用,非漫游网络等。多个Capability之间是“与”的关系,即必须同时满足。上面的代码表示必须没有使用且不是漫游网络。
所有的Transport和Capability定义在NetworkCapabilities中,可查阅该类获知其含义。
//transport列表
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "TRANSPORT_" }, value = {
TRANSPORT_CELLULAR,
TRANSPORT_WIFI,
TRANSPORT_BLUETOOTH,
TRANSPORT_ETHERNET,
TRANSPORT_VPN,
TRANSPORT_WIFI_AWARE,
TRANSPORT_LOWPAN,
})
public @interface Transport { }
//capability列表
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "NET_CAPABILITY_" }, value = {
NET_CAPABILITY_MMS,
NET_CAPABILITY_SUPL,
NET_CAPABILITY_DUN,
NET_CAPABILITY_FOTA,
NET_CAPABILITY_IMS,
NET_CAPABILITY_CBS,
NET_CAPABILITY_WIFI_P2P,
NET_CAPABILITY_IA,
NET_CAPABILITY_RCS,
NET_CAPABILITY_XCAP,
NET_CAPABILITY_EIMS,
NET_CAPABILITY_NOT_METERED,
NET_CAPABILITY_INTERNET,
NET_CAPABILITY_NOT_RESTRICTED,
NET_CAPABILITY_TRUSTED,
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_VALIDATED,
NET_CAPABILITY_CAPTIVE_PORTAL,
NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_FOREGROUND,
NET_CAPABILITY_NOT_CONGESTED,
NET_CAPABILITY_NOT_SUSPENDED,
NET_CAPABILITY_OEM_PAID,
})
public @interface NetCapability { }
什么时候终止监听?只有程序进程退出(注意是进程退出)或解除注册时终止监听。
//解除注册
connectivityManager.unregisterNetworkCallback(networkCallback);
android5.0以下我们改成动态监听CONNECTIVITY_ACTION广播,从而彻底告别隐式监听网络变化带来的性能问题。
定义BroadcastReceiver,
public class NetworkMonitorReceiver extends BroadcastReceiver {
private onNetworkChangedCallback mOnNetworkChangedCallback;
public NetworkMonitorReceiver(onNetworkChangedCallback onNetworkChangedCallback) {
mOnNetworkChangedCallback = onNetworkChangedCallback;
}
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
//网络是否连接可用
boolean isConnected = networkInfo != null && networkInfo.isConnected();
//获取网络类型
String networkType = networkInfo == null ? "none" : networkInfo.getTypeName();
if (mOnNetworkChangedCallback != null) {
//回调监听器
mOnNetworkChangedCallback.onNetworkChanged(isConnected, networkType);
}
}
public static NetworkMonitorReceiver register(Context context, onNetworkChangedCallback callback) {
NetworkMonitorReceiver networkMonitorReceiver = new NetworkMonitorReceiver(callback);
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(networkMonitorReceiver, intentFilter);
return networkMonitorReceiver;
}
public static void unregister(Context context, NetworkMonitorReceiver receiver) {
context.unregisterReceiver(receiver);
receiver.mOnNetworkChangedCallback = null;
}
public interface onNetworkChangedCallback {
void onNetworkChanged(boolean isConnected, String type);
}
}
动态注册广播接收器,
public class MainActivity extends AppCompatActivity implements NetworkMonitorReceiver.onNetworkChangedCallback {
NetworkMonitorReceiver mNetworkMonitorReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNetworkMonitorReceiver = NetworkMonitorReceiver.register(this, this);
}
@Override
public void onNetworkChanged(boolean isConnected, String type) {
//网络发生变化
EasyLogger.d("网络连接可用:" + isConnected + ";网络类型:" + type);
}
@Override
protected void onDestroy() {
super.onDestroy();
NetworkMonitorReceiver.unregister(this, mNetworkMonitorReceiver);
}
}