You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何像JavaScript Promise那样检测Retrofit所有异步操作完成?

你的计数器方案确实能实现需求,但手动维护计数器不仅代码繁琐,还容易出现线程安全问题(比如多个回调同时修改计数器时的竞态条件)。好在Android生态里有两种非常成熟的方案,能实现类似JavaScript中Promise.all的效果,完全不需要手动计数:

方案一:Kotlin协程(Android官方推荐)

如果你的项目已经迁移到Kotlin,或者愿意引入协程依赖,这是最简洁优雅的方案。核心思路是把Retrofit的回调式请求转换成挂起函数,然后用async+awaitAll来并行执行所有请求并等待全部完成。

步骤1:封装回调为挂起函数

先把原来的downloadImage回调转换成挂起函数,让它能在协程中使用:

// 封装成挂起函数,将回调结果转为返回值
suspend fun downloadImage(
    type: String,
    filePath: String,
    imgUrl: String
): Boolean {
    return suspendCoroutine { continuation ->
        SynService.downloadImage(type, filePath, imgUrl, object : SynService.ApiImageCallback {
            override fun onResponse(success: Boolean, requestCounter: Int, errorRequestCounter: Int) {
                // 将回调结果传递给协程
                continuation.resume(success)
            }
        })
    }
}

步骤2:并行执行并等待所有请求

在协程作用域(比如viewModelScope、lifecycleScope)中,遍历你的请求数组,用async启动每个请求,最后用awaitAll等待全部完成:

// 假设你的分类数组是listOf(mpCategory1, mpCategory2, ...)
val categoryList = arrayCategory.toList()

// 并行启动所有下载请求
val deferredResults = categoryList.map { mpCategory ->
    val filePath = "${system.getMp_user_name()}/categorias/${mpCategory.getImg()}"
    // async会立即启动请求,返回一个Deferred(类似JS的Promise)
    async { downloadImage("category", filePath, mpCategory.getImg()) }
}

// 等待所有请求完成,获取结果列表
val results = deferredResults.awaitAll()

// 统计结果并回调
val successCount = results.count { it }
val errorCount = results.size - successCount

val responseObj = hashMapOf(
    "success" to if (errorCount == 0) "1" else "0",
    "message" to if (errorCount == 0) {
        "Sincronização Completada com Sucesso"
    } else {
        "Houve um erro no download das imagens e o processo parou"
    }
)
callback.onResponse(responseObj)

方案二:RxJava(适合Java项目)

如果你的项目是Java语言,或者已经引入了RxJava依赖,可以用RxJava的flatMap+toList组合来实现类似效果,它会自动等待所有Observable完成后再统一处理结果。

步骤1:封装请求为Observable

先把downloadImage封装成返回Observable<Boolean>的方法:

public Observable<Boolean> downloadImageObservable(String type, String filePath, String imgUrl) {
    return Observable.create(emitter -> {
        SynService.downloadImage(type, filePath, imgUrl, new SynService.ApiImageCallback() {
            @Override
            public void onResponse(Boolean success, Integer requestCounter, Integer errorRequestCounter) {
                emitter.onNext(success);
                emitter.onComplete();
            }
        });
    }).onErrorReturnItem(false); // 错误时返回false,避免整个流中断
}

步骤2:批量执行并等待所有结果

用fromIterable遍历请求数组,批量执行后统一处理结果:

// 遍历你的分类数组,转换为Observable流
Observable.fromIterable(arrayCategory)
    .flatMap(mpCategory -> {
        String filePath = system.getMp_user_name() + "/categorias/" + mpCategory.getImg();
        return downloadImageObservable("category", filePath, mpCategory.getImg());
    })
    .toList() // 等待所有Observable完成,收集结果列表
    .subscribe(results -> {
        // 统计成功/失败数量
        int successCount = 0;
        for (Boolean success : results) {
            if (success) successCount++;
        }
        int errorCount = results.size() - successCount;

        HashMap<String, String> responseObj = new HashMap<>();
        if (errorCount == 0) {
            responseObj.put("success", "1");
            responseObj.put("message", "Sincronização Completada com Sucesso");
        } else {
            responseObj.put("success", "0");
            responseObj.put("message", "Houve um erro no download das imagens e o processo parou");
        }
        callback.onResponse(responseObj);
    }, throwable -> {
        // 处理全局错误(比如流初始化失败)
        HashMap<String, String> responseObj = new HashMap<>();
        responseObj.put("success", "0");
        responseObj.put("message", "Houve um erro no processo de sincronização");
        callback.onResponse(responseObj);
    });

为什么这些方案比计数器更好?

  • 无需手动维护状态:不用自己跟踪successCounter、errorCounter,框架自动处理请求的完成状态
  • 线程安全:协程和RxJava都自带线程安全机制,避免了多线程回调修改计数器的竞态问题
  • 代码更简洁:逻辑清晰,可读性更高,减少了重复的计数判断代码
  • 更好的错误处理:可以统一处理全局错误,而不是每个回调单独处理

内容的提问来源于stack exchange,提问作者wavrik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:52:52