在 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() 執行於主執行緒。
class DownloadFileAsync extends AsyncTask<String, Integer, 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;
}
}
@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 實現生命週期感知的異步操作。