【问题标题】:calling an api multiple times using WorkManager in android在android中使用WorkManager多次调用一个api
【发布时间】:2021-10-15 15:35:37
【问题描述】:

我想使用 WorkManager 多次调用一个 api。

其中 idsArrayList 是一个 id 列表。 我将 api 中的每个 id 作为 Path 发送以获取响应,对于其他 id 也是如此。 我希望 workManager 在为所有 id 调用 api 后返回成功。

但问题是 WorkManager 只为列表中的一个 id 返回 SUCCESS。这是我第一次使用 WorkManager,我也尝试通过逐个迭代 idsList 并为 for 循环中的每个 id 创建 workManger 实例来为每个 id 启动工作管理器。但我认为将 idsList 作为工作管理器中的数据发送,然后从 doWork() 内部迭代 id 会更好,但它并没有像我想要的那样工作,我不明白为什么。这是我的代码:

    class MyWorkManager(appContext: Context, workerParams: WorkerParameters):
    Worker(appContext, workerParams) {

    private lateinit var callGrabShifts: Call<ConfirmStatus>

    override fun doWork(): Result {
        val idsList = inputData.getStringArray("IDS_LIST")
        val idsArrayList = idsList?.toCollection(ArrayList())
        var response = ""
        if (idsArrayList != null) {
            try {
      
                response = callConfirmShiftApi(idsArrayList)
                if (response.contains("CONFIRM")) {
                 
                    return Result.success()
                } 
            } catch (e: Exception) {
                e.printStackTrace()
                return Result.failure()
            }
        }

        return Result.retry()
    }

    private fun callConfirmShiftApi(idsArrayList: ArrayList<String>): String {
        var response = ""
        for ((index, id) in idsArrayList.withIndex()) {
         
            response = callApiForId(id)
           
            if(index == idsArrayList.lastIndex) {
                response = "CONFIRM"
            }
        }
        return response
    }

    private fun callApiForId(id: String): String {
        var shiftGrabStatus = ""
      
        callGrabShifts = BaseApp.apiInterface.confirmGrabAllShifts(BaseApp.userId, id)
        callGrabShifts.enqueue(object : Callback<ConfirmStatus> {
            override fun onResponse(call: Call<ConfirmStatus>, response: Response<ConfirmStatus>) {
                if (response.body() != null) {
                    shiftGrabStatus = response.body()!!.status
                    if (shiftGrabStatus != null) {
                        if (shiftGrabStatus.contains("CONFIRM")) {
                            
                            val shiftNumber = ++BaseApp.noOfShiftsGrabbed
                            
                            sendNotification(applicationContext)
                            shiftGrabStatus = "CONFIRM"
                            return
                        } else {
                            shiftGrabStatus = "NOT CONFIRM"
                            return
                        }
                    } else {
                        shiftGrabStatus = "NULL"
                        return
                    }
                } else {
                    shiftGrabStatus = "NULL"
                    return
                }
            }

            override fun onFailure(call: Call<ConfirmStatus>, t: Throwable) {
               
                shiftGrabStatus = "FAILURE"
                return
            }
        })
        return shiftGrabStatus
    }    
}

这是我启动 WorkManager 的代码:

private fun confirmShiftApi(availableShiftsIdList: ArrayList<String>) {
        
        val data = Data.Builder()
        data.putStringArray("IDS_LIST", availableShiftsIdList.toArray(arrayOfNulls<String>(availableShiftsIdList.size)))

        val oneTimeWorkRequest = OneTimeWorkRequestBuilder<MyWorkManager>().setInputData(data.build())
            .build()
        WorkManager.getInstance(applicationContext).enqueue(oneTimeWorkRequest)
      
        WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
            .observe(this, Observer { workInfo: WorkInfo? ->
                if (workInfo != null && workInfo.state.isFinished) {
                    val progress = workInfo.progress           
                }
                Log.d("TESTING", "(MainActivity) : observing work manager - workInfo?.state - ${workInfo?.state}")
            })
    }

有什么我可能做错的建议或任何其他替代方法吗?我选择 workmanager 基本上是为了执行此任务,即使在应用程序关闭时也是为了学习目的,因为我以前没有使用过 WorkManager。但如果这不起作用,会切换到其他选项。

【问题讨论】:

  • 我认为您需要存储库人员,这是我通过将 Worker 视为活动/片段来解决此问题的唯一方法。工作人员对逻辑一无所知,他们的目的只是在存储库中调用一个函数来使用协程 IO 线程执行一些异步任务。
  • 实际问题出在后端,重复调用api返回失败。虽然使用 workmanager,但即使添加延迟也没有太大区别,但使用服务,它在 api 调用之间增加相同的延迟(400 毫秒)时效果更好

标签: android kotlin background-process android-workmanager android-jobscheduler


【解决方案1】:

我尝试了以下方法:

  1. 删除了我用来设置响应的每个方法中的 'var 响应行,虽然我只是为了之前的调试而临时添加了它,但它导致了一个问题。
  2. 我删除了 doWork() 方法中对“CONFIRM”的检查,只是进行了 api 调用,删除了额外的返回行。
  3. 我尝试在每个 ID 的 api 调用之间添加手动延迟。
  4. 我在调用 workmanager 之前从我的活动中删除了发送 ids 数据的代码,并在 workmanager 中进行了 api 调用以获取这些 ids,并在这些调用之间增加了更多延迟,以保持在后台运行以检查数据一轮完成(要为之前获取的所有 id 调用 api,它必须再次调用 api 以检查是否有更多重复的 id)
  5. 我从 onRestart() 和其他需要再次调用 api 的条件中删除了额外的 api 调用。
  6. 我只测试了所有 id 的一轮 api 调用,延迟并删除了重复调用部分,只是为了先测试。没用。

以上都不起作用,它只是删除了额外的代码行。

这是我经过测试的最终代码,它消除了我的疑问。虽然它没有解决这个问题,因为问题是由于后端服务器和 API 在 onResponse 回调中为大多数 id 返回失败(当对每个 id 重复使用 for 循环进行调用时)除了第一个id 和随机列表中的最后一个 id 有时(有延迟)对于其余的 id,它没有使用 Workmanager 从 api 返回 CONFIRM 状态消息。添加延迟并没有太大区别。

这是我的 Workmanager 代码:

    class MyWorkManager(appContext: Context, workerParams: WorkerParameters):
        Worker(appContext, workerParams) {
    
        private lateinit var callGrabShifts: Call<ConfirmStatus>
    
        override fun doWork(): Result {
            val idsList = inputData.getStringArray("IDS_LIST")
            val idsArrayList = idsList?.toCollection(ArrayList())
            if (idsArrayList != null) {
                try {
                    response = callConfirmShiftApi(idsArrayList)
                    if (response.contains("CONFIRM")) {
                        return Result.success()
                    } 
                } catch (e: Exception) {
                    e.printStackTrace()
                    return Result.failure()
                }
            }
            return Result.success()
        }
    
        private fun callConfirmShiftApi(idsArrayList: ArrayList<String>): String {
            for ((index, id) in idsArrayList.withIndex()) {
                response = callApiForId(id)
                Thread.sleep(800)
                if(index == idsArrayList.lastIndex) {
                    response = "CONFIRM"
                }
            }
            return response
        }
    
        private fun callApiForId(id: String): String {
callGrabShifts = BaseApp.apiInterface.confirmGrabAllShifts(BaseApp.userId, id)
 callGrabShifts.enqueue(object : Callback<ConfirmStatus> {
                override fun onResponse(call: Call<ConfirmStatus>, response: Response<ConfirmStatus>) {
                    if (response.body() != null) {
                        shiftGrabStatus = response.body()!!.status
                        if (shiftGrabStatus != null) {
                            if (shiftGrabStatus.contains("CONFIRM")) {
                                return
                            } else {
                                return
                            }
                        } else {
                            return
                        }
                    } else {
                        return
                    }
                }
    
                override fun onFailure(call: Call<ConfirmStatus>, t: Throwable) {
                    return
                }
            })
    
            return shiftGrabStatus
        }

最终这个问题(当对一个 id 进行单独调用时,它总是返回成功,但是当我使用循环为每个 id 调用 api 时,它只返回第一次调用的成功和其他人的失败)使用服务解决了,它也没有从 api 获得完全成功率,但是对于 6/11 ids,api 返回成功(每次 api 调用之间有 400 毫秒的延迟),所以它现在达到了目的。

【讨论】:

    猜你喜欢
    • 2021-12-12
    • 1970-01-01
    • 2022-01-14
    • 2019-04-24
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多