检测网络连通性引发Android无响应(ANR)问题的解决办法
解决Android网络检测导致ANR的问题
问题根源
你的isConnectedToGoogle()方法在主线程中执行ping命令并调用ipProcess.waitFor(),这个方法会阻塞当前线程直到ping命令执行完成。当设备网络信号弱时,ping可能耗时超过5秒,触发Android的「Application Not Responding」(ANR)错误,也就是控制台提示的input dispatching time out。
解决方案
1. 给ping命令添加超时参数
直接修改ping命令,通过-W参数设置超时时间(单位:秒),限制阻塞时长。比如设置为2秒,超过则直接判定为无法连接:
public boolean isConnectedToGoogle() { Runtime runtime = Runtime.getRuntime(); boolean reachGoogle = false; try { // -c 1: 发送1个ping包;-W 2: 超时2秒(注意是大写W) Process ipProcess = runtime.exec("/system/bin/ping -c 1 -W 2 8.8.8.8"); int exitValue = ipProcess.waitFor(); reachGoogle = exitValue == 0; } catch (IOException e) { reachGoogle = false; } catch (InterruptedException e) { reachGoogle = false; Thread.currentThread().interrupt(); // 恢复线程中断状态,避免后续逻辑异常 } return reachGoogle; }
2. 绝对不要在主线程执行网络检测
即使加了超时,主线程执行阻塞操作仍然存在风险。必须将网络检测逻辑放到后台线程执行,通过回调返回结果:
步骤1:定义回调接口
public interface NetworkCheckCallback { void onNetworkCheckResult(boolean isNetworkNull); }
步骤2:修改CheckNetwork类,异步执行检测
public class CheckNetwork { // 原isConnectedToGoogle()方法(已加超时) public boolean isConnectedToGoogle() { /* ... */ } // 原isNetworkNull()方法 public boolean isNetworkNull(Context context) { /* ... */ } // 新增异步检测方法 public void checkNetworkAsync(Context context, NetworkCheckCallback callback) { // 用单线程线程池执行后台任务 ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(() -> { boolean result = isNetworkNull(context); // 切换回主线程回调结果 new Handler(Looper.getMainLooper()).post(() -> { callback.onNetworkCheckResult(result); }); executor.shutdown(); }); } }
步骤3:调用异步方法
CheckNetwork checkNetwork = new CheckNetwork(); checkNetwork.checkNetworkAsync(getApplicationContext(), isNetworkNull -> { if (isNetworkNull) { // 无网络逻辑 } else { // 有网络逻辑 } });
3. 优先使用系统API检测网络连通性
Android从API 29(Android 10)开始提供了更可靠的网络验证API,无需自己实现ping,系统会自动验证网络是否能访问互联网:
public boolean isNetworkValid(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (cm == null) return false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Network activeNetwork = cm.getActiveNetwork(); if (activeNetwork == null) return false; NetworkCapabilities capabilities = cm.getNetworkCapabilities(activeNetwork); // NET_CAPABILITY_VALIDATED表示系统已验证网络可访问互联网 return capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); } else { // 适配旧版本:先检查网络连接,再异步执行ping NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); if (activeNetwork == null || !activeNetwork.isConnected()) return false; // 这里的isConnectedToGoogle()必须在后台线程调用 return isConnectedToGoogle(); } }
关键注意事项
- 任何阻塞性的网络操作(包括ping、HTTP请求)都不能在主线程执行,必须放到后台线程。
- 优先使用系统提供的
NetworkCapabilities.NET_CAPABILITY_VALIDATED,避免自己实现网络连通性检测,减少出错概率。 - 如果必须使用ping,一定要添加超时参数,同时在后台线程执行。
内容的提问来源于stack exchange,提问作者Jason W
相关产品推荐
相关产品推荐

