Android判断网络是否可用、区分WiFi和数据、是否被安全软件拦截
2018-12-29 liuyingcong 安卓开发
网络请求失败的原因有很多,手机没有连网是很常见的原因,这时需要提醒用户打开网络。怎么从众多可能的失败原因中判断是不是手机没连网呢?
播放视频或者声音是很费流量的,如果用户用的是数据而非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和服务器时间戳之类的请求应该拦截器获取;页面中也不能完全依赖于自动刷新,还需要增加手动刷新、失败重试的功能。