Android判断网络是否可用、区分WiFi和数据、是否被安全软件拦截

网络请求失败的原因有很多,手机没有连网是很常见的原因,这时需要提醒用户打开网络。怎么从众多可能的失败原因中判断是不是手机没连网呢?

播放视频或者声音是很费流量的,如果用户用的是数据而非WiFi,就需要提醒他是否继续使用。怎么判断手机当前的网络是WiFi还是数据呢?

手机连着网,但是用户在安全软件中设置了本应用禁用网络,这种情况与手机没联连网是不一样的。怎么能区分出来并提示用户呢?

下面我们一一解答以上问题:

网络请求失败后,首先要判断手机是否联连着网,谷歌提供了网络连接的系统服务,可以用来判断手机是否连网:

// 判断网络是否可用

public static boolean isNetworkAvailable(Context context) {

ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

if (manager !=null){

NetworkInfo info = manager.getActiveNetworkInfo();

return info != null && info.isAvailable();

} else {

return false;

}

}

调用以上方法,如果返回false,提示用户“网络不可用,请检查网络设置”就好了。

有些情况下我们要实时接收网络状态的变化,这就需要注册广播接收者,接收网络状态的变化:

// 广播接收者,接收网络状态的变化

class NetworkChangeReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkInfo networkInfo = manager.getActiveNetworkInfo();

if (networkInfo != null && networkInfo.isAvailable()) {

// 有网了

...

} else {

// 断网了

...

}

}

}

注册广播接收者:

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");

networkChangeReceiver = new NetworkChangeReceiver();

registerReceiver(networkChangeReceiver, intentFilter);

}

取消注册:

@Override

protected void onDestroy() {

super.onDestroy();

unregisterReceiver(networkChangeReceiver);

}

对于只需要运行一次就够了的代码,可以在“有网了”的地方需要运行的代码后面取消注册。

以上广播接收者,会在注册之后接收一次,不会等到下次网络变化时才第一次接收。适用于用户进入APP之前没有打开网络,进入之后才去开启网络的情况,开启网络之后做一次网络请求刷新数据。

对于第二个问题,要分辨用户当前使用的是WiFi还是数据网络

// 获取当前网络类型

public String getNetworkType(Context context) {

ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

NetworkInfo mobileInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

if (wifiInfo != null && wifiInfo.isConnectedOrConnecting()) {

return "wifi_network";

} else if (mobileInfo != null && mobileInfo.isConnectedOrConnecting()) {

return "mobile_network";

} else {

return "no_network";

}

}

当然,也可以实时获取,注册广播接收者即可,前面写过,不再赘述。

对于第三个问题,比较麻烦,安全软件禁用当前APP的网络之后,调用网络是否可用的方法返回的是true,但是网络请求都是失败的,这时只能从失败原因里去找:

网络请求失败了,并且排除了手机没有连网的原因之后,如果以下代码成立,则很有可能是被安全管家禁网了:

if (e instanceof SocketException && e.getMessage().equals("Network is unreachable")) {

Toast.makeText(context, "网络请求失败,APP可能被安全软件禁网了", Toast.LENGTH_SHORT).show();

}

由于存在这种被安全管家禁网并且不能在网络请求之前判断出来,当然也不能实时监测出来,所以对于获取token和服务器时间戳之类的请求应该拦截器获取;页面中也不能完全依赖于自动刷新,还需要增加手动刷新、失败重试的功能。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐