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

Android AsyncTask 串行執行:onPostExecute 中啟動下一個異步任務正確姿勢

     編輯:程式設計綜合問答

場景描述

第一個 AsyncTask 解析 JSON 獲取圖片 URL,需在 onPostExecute 中下載圖片,但直接在 onPostExecute 做網絡請求會阻塞 UI 線程或報錯。

核心原則

onPostExecute 運行在主線程,不能執行耗時操作。必須啟動新的異步任務或線程池執行後續工作。

方案一:Handler 傳遞消息啟動新任務(標準)

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 / Kotlin 協程(現代化)

// 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)
}

避坑指南

  • 不要在 onPostExecute new Thread():頻繁創建線程開銷大,用線程池。
  • AsyncTask 已棄用 (API 30);新項目請直接用协程/RxJava/ExecutorService。
  • 內存洩漏:AsyncTask/Handler/Runnable 持有外部類引用必須用 WeakReference 或在 onDestroy 取消任務。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved