如何像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
相关产品推荐
相关产品推荐

