使用AsyncTask实时检测网络连接遇NetworkOnMainThreadException问题求助
问题分析与解决方案
你遇到的NetworkOnMainThreadException即便用了AsyncTask仍出现,大概率是这几个核心问题导致的:
1. 构造函数名称错误(最常见原因)
你的类名是CheckNetWorkConnection,但构造函数写成了checkNetWorkConnection(首字母小写)——这在Java里不是构造函数,只是普通方法。实例化时会调用默认无参构造,导致activity变量未初始化,后续操作极可能在错误线程执行网络逻辑。
2. 网络检测逻辑未放在doInBackground中
只有AsyncTask的doInBackground方法运行在子线程,如果你的网络检测代码(比如发起网络请求、ping地址)写在onPreExecute/onPostExecute等主线程方法里,必然会抛出异常。
修正后的AsyncTask实现代码
以下是修复后的完整代码,同时加入了内存泄漏防护和两种网络检测方案:
class CheckNetworkConnection extends AsyncTask<Void, Void, Boolean> { // 用WeakReference持有Activity,避免内存泄漏 private final WeakReference<MyActivity> activityRef; // 构造函数必须与类名完全一致 public CheckNetworkConnection(MyActivity activity) { this.activityRef = new WeakReference<>(activity); } @Override protected Boolean doInBackground(Void... params) { MyActivity activity = activityRef.get(); // 先判断Activity是否存活,避免空指针 if (activity == null || activity.isFinishing()) { return false; } // 方案1:仅检测系统是否有网络连接(无需实际请求,可在主线程执行,放在这里也没问题) ConnectivityManager cm = (ConnectivityManager) activity.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); boolean hasBasicNetwork = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); // 方案2:验证网络是否真的能访问互联网(需发起网络请求,必须放在子线程) if (hasBasicNetwork) { try { URL url = new URL("http://www.google.com"); HttpURLConnection urlc = (HttpURLConnection) url.openConnection(); urlc.setConnectTimeout(3000); urlc.setReadTimeout(3000); urlc.setRequestMethod("HEAD"); // 用HEAD请求更轻量 return urlc.getResponseCode() == HttpURLConnection.HTTP_OK; } catch (IOException e) { e.printStackTrace(); return false; } } return hasBasicNetwork; } @Override protected void onPostExecute(Boolean isNetworkAvailable) { MyActivity activity = activityRef.get(); if (activity == null || activity.isFinishing()) { return; } // 在主线程更新UI:显示/隐藏TextView TextView networkStatusTv = activity.findViewById(R.id.network_status_tv); networkStatusTv.setVisibility(isNetworkAvailable ? View.GONE : View.VISIBLE); } }
调用方式(在Activity中)
new CheckNetworkConnection(this).execute();
更高效的替代方案:实时监听网络状态
如果你需要实时检测网络变化,Android 10+官方推荐使用ConnectivityManager.NetworkCallback,比定时执行AsyncTask更高效,也不会有线程问题:
private ConnectivityManager.NetworkCallback networkCallback; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); networkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { // 网络可用,切换到主线程更新UI runOnUiThread(() -> { TextView networkStatusTv = findViewById(R.id.network_status_tv); networkStatusTv.setVisibility(View.GONE); }); } @Override public void onLost(Network network) { // 网络断开,切换到主线程更新UI runOnUiThread(() -> { TextView networkStatusTv = findViewById(R.id.network_status_tv); networkStatusTv.setVisibility(View.VISIBLE); }); } }; // 注册网络监听请求 NetworkRequest request = new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build(); cm.registerNetworkCallback(request, networkCallback); } @Override protected void onDestroy() { super.onDestroy(); // 注销监听,避免内存泄漏 ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); cm.unregisterNetworkCallback(networkCallback); }
内容的提问来源于stack exchange,提问作者Constantin N.
相关产品推荐
相关产品推荐

