第一個 AsyncTask 解析 JSON 獲取圖片 URL,需在 onPostExecute 中下載圖片,但直接在 onPostExecute 做網絡請求會阻塞 UI 線程或報錯。
onPostExecute 運行在主線程,不能執行耗時操作。必須啟動新的異步任務或線程池執行後續工作。
private static class MyHandler extends Handler {
private final WeakReference ref;
MyHandler(OuterClass outer) { ref = new WeakReference<>(outer); }
@Override
public void handleMessage(Message msg) {
OuterClass outer = ref.get();
if (outer != null) outer.startNextTask((String) msg.obj);
}
}
private final Handler handler = new MyHandler(this);
protected void onPostExecute(List urls) {
if (urls != null && !urls.isEmpty()) {
Message msg = handler.obtainMessage(MSG_DOWNLOAD_IMG, urls.get(0));
msg.sendToTarget();
}
}
private void startNextTask(String imgUrl) {
new ImageDownloadTask().execute(imgUrl); // 新 AsyncTask
}
private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
protected void onPostExecute(List urls) {
if (urls != null && !urls.isEmpty()) {
EXECUTOR.submit(() -> {
// 后台下載圖片
Bitmap bitmap = downloadImage(urls.get(0));
// 回主線程更新 UI
runOnUiThread(() -> imageView.setImageBitmap(bitmap));
});
}
}
// RxJava
Observable.fromCallable(() -> parseJson())
.subscribeOn(Schedulers.io())
.flatMap(urls -> Observable.fromIterable(urls)
.flatMap(this::downloadImage)
.toList())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmaps -> updateUI(bitmaps));
// Kotlin 協程
lifecycleScope.launch {
val urls = withContext(Dispatchers.IO) { parseJson() }
val bitmaps = urls.map { url -> withContext(Dispatchers.IO) { downloadImage(url) } }
updateUI(bitmaps)
}
WeakReference 或在 onDestroy 取消任務。