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

Android AsyncTask 下載圖片時 CalledFromWrongThreadException 異常完整解析

     編輯:程式設計綜合問答

在 Android 中使用 AsyncTask 下載圖片並顯示時,若在背景執行緒中直接操作 UI 元件,會拋出 ViewRoot$CalledFromWrongThreadException 異常。

錯誤代碼分析

class DownloadFileAsync extends AsyncTask<String, String, String> {
    @Override
    protected String doInBackground(String... aurl) {
        // ... 下載邏輯 ...
        // 錯誤:在背景執行緒中操作 UI
        image.setImageBitmap(bitmap); 
        for(int l=0; l<4; l++) {
            if(listObject.get(l).getImage() != "") 
                image.setImageBitmap(bitmap); // 重複錯誤
        }
        return null;
    }
    
    @Override
    protected void onPostExecute(String unused) {
        image.setImageBitmap(bitmap); // 這裡正確
        dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
    }
}

核心原則

Android UI 操作必須在主執行緒(UI 執行緒)中進行。AsyncTask 的 doInBackground() 執行於背景執行緒,onPostExecute()、onProgressUpdate()、onPreExecute() 執行於主執行緒。

完整修正方案

1. 修正泛型參數:結果型別改為 Bitmap

class DownloadFileAsync extends AsyncTask<String, Integer, Bitmap> {

2. doInBackground 返回下載的 Bitmap

@Override
protected Bitmap doInBackground(String... aurl) {
    try {
        URL url = new URL(aurl[0]);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(10000);
        conn.setReadTimeout(10000);
        conn.connect();
        
        InputStream is = conn.getInputStream();
        Bitmap bitmap = BitmapFactory.decodeStream(is);
        bitmap = Bitmap.createScaledBitmap(bitmap, 70, 70, true);
        
        // 可選:發布進度
        // publishProgress(progress);
        
        return bitmap;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

3. onPostExecute 在主執行緒安全更新 UI

@Override
protected void onPostExecute(Bitmap bitmap) {
    if (bitmap != null) {
        image.setImageBitmap(bitmap);
    }
    dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
}

進階優化建議

  • 使用 Glide、Picasso、Coil 等成熟圖片載入庫替代手動下載
  • 大圖片考慮使用 inSampleSize 縮放載入避免 OOM
  • 添加快取機制避免重複下載
  • 處理配置變更(如螢幕旋轉)時的任務取消與重啟

現代替代方案

新專案建議使用 Kotlin Coroutines + Flow 或 RxJava 替代 AsyncTask(已棄用),配合 ViewModel 實現生命週期感知的異步操作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved