Search code examples
androidkotlinkotlin-coroutinesandroid-workmanager

WorkManager: Awaiting work does not seem to wait for work to finish?


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 -> {}
    }
}

Solution

  • 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.