首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 開發:解決 NetworkOnMainThreadException 異常——將網絡請求移至 AsyncTask doInBackground

     編輯:程式設計綜合問答

異常現象

在 AsyncTask.onPostExecute 中調用 TwitterUtils.isAuthenticated(),該方法內部執行網絡請求 twitter.getAccountSettings(),拋出 NetworkOnMainThreadException。原因是 onPostExecute 運行在主線程,Android 4.0+ 禁止主線程執行網絡操作。

核心解決方案:網絡請求移至 doInBackground

class CallNetworkMethod extends AsyncTask {
    // 使用 Boolean 作為結果類型,直接返回認證狀態
    
    @Override
    protected Boolean doInBackground(Void... params) {
        // 關鍵:在後台線程執行網絡請求
        return TwitterUtils.isAuthenticated(prefs);
    }
    
    @Override
    protected void onPostExecute(Boolean isAuthenticated) {
        // 主線程更新 UI
        loginStatus.setText("Logged into Twitter: " + isAuthenticated);
        // 可根據結果進一步處理
        if (isAuthenticated) {
            // 已認證邏輯
        } else {
            // 未認證,跳轉授權頁面
            Intent i = new Intent(getApplicationContext(), TwPrepareRequestTokenActivity.class);
            i.putExtra("tweet_msg", getTweetMsg());
            startActivity(i);
        }
    }
}

TwitterUtils 保持不變(純網絡邏輯)

public class TwitterUtils {
    public static boolean isAuthenticated(SharedPreferences prefs) {
        String token = prefs.getString(OAuth.OAUTH_TOKEN, "");
        String secret = prefs.getString(OAuth.OAUTH_TOKEN_SECRET, "");
        AccessToken a = new AccessToken(token, secret);
        Twitter twitter = new TwitterFactory().getInstance();
        twitter.setOAuthConsumer(TwConstants.CONSUMER_KEY, TwConstants.CONSUMER_SECRET);
        twitter.setOAuthAccessToken(a);
        try {
            twitter.getAccountSettings(); // 網絡請求
            return true;
        } catch (TwitterException e) {
            return false;
        }
    }
}

AsyncTask 關鍵泛型參數說明

參數含義本例
Params執行參數類型Void(無參數)
Progress進度類型Void(無進度)
Result結果類型Boolean(認證結果)

現代替代方案(推薦)

AsyncTask 已在 Android 11 (API 30) 棄用,建議使用:

1. Kotlin 協程 + Retrofit/OkHttp


// ViewModel 中
viewModelScope.launch {
    try {
        val isAuth = withContext(Dispatchers.IO) { 
            TwitterUtils.isAuthenticated(prefs) 
        }
        _loginStatus.postValue("Logged into Twitter: $isAuth")
    } catch (e: Exception) {
        _loginStatus.postValue("Error: ${e.message}")
    }
}

2. RxJava

Observable.fromCallable(() -> TwitterUtils.isAuthenticated(prefs))
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(isAuth -> loginStatus.setText("Logged: " + isAuth),
               error -> loginStatus.setText("Error: " + error.getMessage()));

3. ExecutorService + Handler(純 Java)

ExecutorService executor = Executors.newSingleThreadExecutor();
Handler mainHandler = new Handler(Looper.getMainLooper());

executor.execute(() -> {
    boolean isAuth = TwitterUtils.isAuthenticated(prefs);
    mainHandler.post(() -> loginStatus.setText("Logged: " + isAuth));
});

最佳實踐檢查清單

  • ✅ 所有網絡 I/O、文件 I/O、數據庫操作、耗時計算放入後台線程。
  • ✅ UI 更新(setText、setVisibility、Toast、Dialog)必須在主線程。
  • ✅ 使用 StrictMode.ThreadPolicy 開發期檢測主線程違規。
  • ✅ 棄用 AsyncTask,遷移至協程/RxJava/ExecutorService。
  • ✅ 生命週期感知:使用 lifecycleScope/viewModelScope 自動取消。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved