须知:Android7.0起网络变化监听隐式广播被关闭
在 Android 7.0 版本中除了提供诸多多窗口支持、活动通知、后台优化、消息传递服务和Vulkan 等新特性和功能外,还对系统和 API 行为做出了各种变更,其中最重要的一点:Android7.0为了进行后台的优化删除了三项隐式广播(网络状态变更广播、拍照广播以及录像广播),以帮助优化内存使用和电量消耗。 此项变更很有必要,比如说网络变化的广播(CONNECTIVITY_CHANGE),当网络发生变化时所有注册了隐式监听网络变化的app都会被启动。删除这些广播可以显著提升设备性能和用户体验。同样地,拍照广播和录视频广播(ACTION_NEW_PICTURE or ACTION_NEW_VIDEO)也会出现上述情况。
该变更导致在Android N平台下即使在Manifest.xml清单文件中注册了 CONNECTIVITY_ACTION广播,在网络发生变化时也不会接收到任何的信息。但是正在前台运行的应用程序如果在主线程中通过Context.registerReceiver()动态注册了CONNECTIVITY_ACTION广播,该应用程序仍然可以接收到该广播。(注:这样开发者就可以根据不同的网络状态加载相应的页面信息了,从而提高用户体验)。
总结:为了避免Android7.0版本接收不到系统网络变化的广播,强烈建议使用动态注册广播的形式来注册广播。
1,添加权限
<!-- 访问网络. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 访问WiFi状态. -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 访问网络状态, 检测网络的可用性. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2,编写网络监听工具类
工具类见本人博客:安卓项目实战之:网络连接判断工具类
直接Copy过来用即可。
3,新建一个接口来接收状态变化的回调
public interface INetEvent {
void onNetChange(int netWorkState);
}
4,新建一个BroadcastReceiver,监听网络状态变化
public class NetStateReceiver extends BroadcastReceiver {
private INetEvent mINetEvent= BaseActivity.mINetEvent;
@Override
public void onReceive(Context context, Intent intent) {
// 如果相等的话就说明网络状态发生了变化
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
//容错机制
if(mINetEvent!=null) {
// 接口回调传过去状态的类型
mINetEvent.onNetChange(NetWorkUtils.getNetWorkState(context));
}
}
}
}
5,在清单文件中配置 (该步骤取消,为适配7.0已在BaseActivity中动态注册)
<!-- 监听网络变化的广播 -->
<receiver
android:name=".receiver.NetStateReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
6,在基类BaseActivity中实现INetEvent接口
public abstract class BaseActivity extends AppCompatActivity implements INetEvent {
public static INetEvent mINetEvent;
// 网络状态变化的广播接收器
private NetStateReceiver mNetStateReceiver;
// 当前网路连接状态,网络状态发生变化,该值会动态更新
// -1:没有网络 0:移动网络 1:wifi网络
protect int netWorkState;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//初始化网络状态的监听
mINetEvent=this;
// 初始化时检查网络连接
checkNet();
// 动态注册网络状态监听广播
mNetStateReceiver = new NetStateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(mNetStateReceiver , filter);
}
/**
* 初始化时获取当前网络状态
*/
public void checkNet() {
this.netWorkState= NetWorkUtils.getNetWorkState(BaseActivity.this);
}
/**
* 全局检测网络广播的回调 处理网络变化
* @param netWorkState 网络状态 -1:没网络 0:移动网络 1:WiFi网络
*/
public abstract void onNetChanged(int netWorkState);
@Override
public void onNetChange(int netWorkState) {
this.netWorkState= netWorkState;
onNetChanged(netWorkState);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消注册
unregisterReceiver(mNetStateReceiver);
}
}
7,具体Activity的实现
public class NetStateActivity extends BaseActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_netstate);
}
@Override
public void onNetChanged(int netWorkState) {
switch (netWorkState) {
case NetWorkUtils.NETWORK_NONE:
//没有网络
break;
case NetWorkUtils.NETWORK_MOBILE:
//移动网络
break;
case NetWorkUtils.NETWORK_WIFI:
//WiFi网络
break;
}
}
}
广播监听只有在网络状态发生变化的情况下才会触发回调,因此当第一次在没网时启动app的时候,该监听并不会回调,所以我们需要在第一次启动app时做手动的判断,上面的处理中我们每次在Activity界面初始化的时候进行了网络判断,并且将获取到的网络值传给了成员变量netWorkState,所以我们可以直接获取该值进行网络状态判断:
// netWorkState就是继承的父类的成员变量
Toast.makeText(this, "当前网络状态:"+netWorkState, Toast.LENGTH_SHORT).show();