实现实时监控网络变化,类似于微信的功能,当网络不可用时app能实时感知到,网上找了很多例子并不能实现,或者只实现其中一部分功能,我就参考大家的方法做一个组合。
一、网络状态变化监测,此方式只能监测网络连接改变,不能判断是否可用(例如网络连接正常,但是不能访问网络)。
在使用时定义一个方法,名字随便,参数必须是一个NetWorkState类型:
// 监听网络变化类型
@NetWorkMonitor(monitorFilter = {NetWorkState.WIFI, NetWorkState.GPRS, NetWorkState.NONE})
public void onNetworkStateChange(NetWorkState workState) {
// workState包含三种类型
}
二、判断网络连接是否可用
经过测试NetworkInfo.isAvailable()此方式也不能判断连接的网络是否可用。
比较靠谱的是通过ping一个公网地址的方式:
ping命令有几个参数,可百度查阅。
public boolean isAvailable() {
Runtime runtime = Runtime.getRuntime();
try {
// 会阻塞线程 ping baidu 1次
Process exec = runtime.exec("ping -c 1 www.baidu.com");
int i = exec.waitFor();
//wifi不可用或未连接,返回2;WiFi需要认证,返回1;WiFi可用,返回0;
return i == 0;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
但是此方法会阻塞线程,不能在主线程执行,自然想到通过子线程执行,但是在测试中我发现,假如从wifi1切换到wifi2(移动网络开启的),执行顺序是:NONE->GPRS->WIFI,有多个状态,如果在这些个状态变化时执行上面方法,并不一定是按顺序返回结果,所以我才用任务队列的方式去执行。
在使用时:
public class MainActivity extends AppCompatActivity {
private String[] permissions = {
Manifest.permission.READ_PHONE_STATE
};
private NetQueue netQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions, 1);
}
// 创建单任务队列,任务按顺序依次执行。
netQueue = new NetQueue(1);
netQueue.start();
}
// 监听网络变化类型
@NetWorkMonitor(monitorFilter = {NetWorkState.WIFI, NetWorkState.GPRS, NetWorkState.NONE})
public void onNetworkStateChange(NetWorkState workState) {
NetCheckTask task = new NetCheckTask(this, isAvailable -> {
Log.e("MainActivity", "onResult:" + (isAvailable ? "网络可用" : "网络不可用") + ", Thread:" + Thread.currentThread().toString());
}
);
netQueue.add(task);
}
@Override
protected void onStart() {
super.onStart();
NetManager.getInstance().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
NetManager.getInstance().unregister(this);
}
}
NetCheckTask类:
public class NetCheckTask implements ITask {
private Context context;
private NetCheckCallback callback;
public NetCheckTask(Context context, NetCheckCallback callback) {
this.context = context;
this.callback = callback;
}
@Override
public void checkNet() {
// do something
Runtime runtime = Runtime.getRuntime();
try {
// 会阻塞线程 ping baidu 1次
Process exec = runtime.exec("ping -c 1 www.baidu.com");
int i = exec.waitFor();
//wifi不可用或未连接,返回2;WiFi需要认证,返回1;WiFi可用,返回0;
if (context != null && callback != null) {
new Handler(context.getMainLooper()).post(() -> callback.onResult(i == 0));
}
} catch (Exception e) {
e.printStackTrace();
// 异常处理
}
}
}
此方法只能在网络切换时才会判断网络是否可用,微信可以在不切换网络时监测是否可用,我猜这是基于他们的IM系统做的,如果我们也想达到这种效果也是可以的,例如轮询调用ping方法等。