英文:
WorkManager: Awaiting work does not seem to wait for work to finish?
问题
我试图启动一个工作请求来从远程源获取数据,然后将数据插入到Room数据库中。
工作器处理数据的获取和插入到Room数据库中。
在存储库中,我对WorkManager排队了一个工作请求:
// ...
private val workManager = WorkManager.getInstance(context)
private val imageDao = database.imageDao()
suspend fun getImages(): List<Images> {
// ...
workManager.apply {
enqueueUniqueWork(
uniqueWorkName,
ExistingWorkPolicy.KEEP,
OneTimeWorkRequestBuilder<FetchImagesWorker>()
.setConstraints(constraints)
.build()
)
.await()
}
return imageDao.getAll()
}
工作请求成功运行。然而,在函数中的return imageDao.getAll()
这一行尝试访问Room数据库,但工作请求返回Success
之前。
我在这个示例中对唯一工作使用了await()
。
然而,是否使用await()
似乎没有任何区别。此外,Worker
类中的工作位于withContext(Dispatchers.IO)
块中,但似乎是否存在也没有区别。
有没有什么方法可以在函数返回来自Room数据库的结果之前等待工作请求完成?
先谢谢。
编辑:
返回一个Flow<List<Image>>
而不是List<Image>
。
然后:
val workStatesFlow = workManager.getWorkInfosForUniqueWorkLiveData(uniqueWorkName).asFlow()
workStatesFlow.map { workInfos ->
workInfos.first().state
}.collect { workState ->
when (workState) {
WorkInfo.State.SUCCEEDED -> {
emit(imageDao.getAll())
}
else -> {}
}
}
英文:
I am trying to start a work request to fetch data from a remote source then insert the data into a Room database.
The worker handles fetching and inserting data into the Room database.
In the repository, I enqueue a work request for WorkManager:
// ...
private val workManager = WorkManager.getInstance(context)
private val imageDao = database.imageDao()
suspend fun getImages(): List<Images> {
// ...
workManager.apply {
enqueueUniqueWork(
uniqueWorkName,
ExistingWorkPolicy.KEEP,
OneTimeWorkRequestBuilder<FetchImagesWorker>()
.setConstraints(constraints)
.build()
)
.await()
}
return imageDao.getAll()
}
The work request runs successfully. However, the function attempts to access the Room database in the line return imageDao.getAll()
before the work request returns Success
.
I use await()
on the unique work from this example.
However, it does not seem to make a difference having await()
or not. Also, the work in the Worker
class is within a withContext(Dispatchers.IO)
block, but again, it does not seem to make a difference if it's there or not.
Any ideas how I can await the work request to finish before the function returns the results from the Room database?
Thanks in advance.
EDIT:
Return a Flow<List<Image>>
instead of List<Image>
.
Then:
val workStatesFlow = workManager.getWorkInfosForUniqueWorkLiveData(uniqueWorkName).asFlow()
workStatesFlow.map { workInfos -> workInfos.first().state }.collect { workState ->
when (workState) -> {
WorkInfo.State.SUCCEEDED -> {
emit(imageDao.getAll())
}
else -> {}
}
}
答案1
得分: 0
你的代码问题在于工作请求的调用是异步的,这意味着它不会阻塞线程,并将继续执行下一行代码。这就是为什么你在尝试访问 Room 数据库之前遇到问题的原因。
为了在访问 Room 数据库之前等待工作请求的完成,你需要使用一个 LiveData 对象,Worker 可以在完成任务后更新它。然后,你可以从存储库或 ViewModel 中观察这个 LiveData 对象,只有当 LiveData 对象被更新为工作请求的结果时,才返回 Room 数据库的结果。
英文:
The issue with your code is that the call to enqueue the work request is asynchronous, meaning that it will not block the thread and will continue executing the next lines of code. This is why you are experiencing the issue of attempting to access the Room database before the work request completes.
To await the completion of the work request before accessing the Room database, you need to use a LiveData object that the Worker can update when it completes the task. Then, you can observe this LiveData object from your repository or ViewModel, and return the Room database results only when the LiveData object is updated with the result of the work request.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论