Android使用WorkManager批量调用API完成后统一返回成功问题求助
问题诊断
你的代码核心有三个错误点:
- 你使用的默认
Worker类的doWork方法是同步执行的,方法执行结束就会直接返回任务结果,不会等待你发起的异步API回调。你调用Retrofit的enqueue方法发起异步请求后,doWork不会等待回调执行就会继续往下走,导致Worker结束时大部分API请求还没有返回结果。 callApiForId方法中,你直接返回初始化的空值shiftGrabStatus,异步回调还没执行,返回值永远是空字符串。你后续在callConfirmShiftApi中直接在循环到最后一个元素时硬编码response = "CONFIRM",等于完全忽略了所有API的真实返回结果。- 你把
callGrabShifts声明为类成员变量,每次循环调用API都会覆盖上一个请求的Call实例,会导致前面的请求回调异常、甚至被意外取消。
推荐解决方案
改用官方提供的CoroutineWorker实现,配合Retrofit的挂起函数能力,用同步写法执行异步请求,保证所有API请求执行完成后再返回Worker结果。
步骤1:修改API接口定义
将你的接口方法改为挂起函数,无需返回Call类型:
// 原代码:fun confirmGrabAllShifts(userId: String, id: String): Call<ConfirmStatus> // 修改为: suspend fun confirmGrabAllShifts(userId: String, id: String): Response<ConfirmStatus>
步骤2:替换Worker实现
// 需引入work-runtime-ktx依赖 class MyWorkManager(appContext: Context, workerParams: WorkerParameters): CoroutineWorker(appContext, workerParams) { override suspend fun doWork(): Result { val idsList = inputData.getStringArray("IDS_LIST") ?: return Result.failure() var allRequestSuccess = true try { // 按顺序遍历所有id执行请求,会等待前一个请求返回后再执行下一个 for (id in idsList) { val response = BaseApp.apiInterface.confirmGrabAllShifts(BaseApp.userId, id) if (response.isSuccessful && response.body()?.status?.contains("CONFIRM") == true) { // 请求成功逻辑 val shiftNumber = ++BaseApp.noOfShiftsGrabbed sendNotification(applicationContext) } else { // 单个请求失败,按需设置整体任务状态 allRequestSuccess = false // 如果要求所有请求必须全部成功才返回成功,可直接break return Result.failure() } } } catch (e: Exception) { e.printStackTrace() // 网络异常等情况可返回重试 return Result.retry() } return if (allRequestSuccess) Result.success() else Result.failure() } }
启动Worker的逻辑不需要修改,原有代码可直接复用。
替代实现思路
如果你需要每个id的请求可以独立重试、互不影响,可以为每个id单独创建一个OneTimeWorkRequest,通过WorkManager的链式任务能力批量执行,所有子任务全部成功后才会返回整体成功:
private fun confirmShiftApi(availableShiftsIdList: ArrayList<String>) { val workList = availableShiftsIdList.map { id -> val data = Data.Builder().putString("SHIFT_ID", id).build() OneTimeWorkRequestBuilder<SingleIdWorkWorker>().setInputData(data).build() } WorkManager.getInstance(applicationContext) .beginWith(workList) .enqueue() // 可监听整体任务的执行状态 }
你只需要单独实现一个处理单个id请求的Worker即可。
内容的提问来源于stack exchange,提问作者Pooja Singh
相关产品推荐
相关产品推荐

