Android Shorts 🩳: WorkManager — Observing a WorkRequest (level paranoid)
Start a work request
(see how-to-hilt+workmanager in the previous episode)
A method in a ViewModel will do:
fun startTodoWork() {
viewModelScope.launch {
val oneTimeWorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
.addTag("myTag")
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
workManager.enqueueUniqueWork(
"uniqueWorkName",
ExistingWorkPolicy.REPLACE,
oneTimeWorkRequest
)
}
}ViewModel.kt
Observing the state
WorkManager.getWorkInfoByIdLiveData returns LiveData , which isn’t really useful at the moment.
Turn that into a flow by adding the livedata-ktx dependency.
dependencies {
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
}build.gradle.kts
Print out the state of the work request while you are at it.
workManager.enqueueUniqueWork(
....
)
workManager.getWorkInfoByIdLiveData(oneTimeWorkRequest.id).asFlow().collect {
Log.d("TAG", it?.state?.name!!)
}ViewModel.kt
Job done.
Or maybe..
The collection will be alive as long as the ViewModel is alive, patiently waiting for updates for a job that might be finished already.
Imagine starting a lot of work requests here. Clean up is in order.
supervisorScope {
launch {
Log.d("TAG", "WorkRequest - state observation - start")
workManager.getWorkInfoByIdLiveData(oneTimeWorkRequest.id).asFlow().collect {
Log.d("TAG", "WorkRequest - ${it?.state?.name!!}")
if (it.state.isFinished) {
Log.d("TAG", "WorkRequest - Work finished")
cancel() // cancel the supervisorScope, it is now redundant
}
}
}
}.invokeOnCompletion {
Log.d("TAG", "WorkRequest - state observation - end")
}ViewModel.kt
supervisorScope?
Calling cancel() on the supervisorScope will cancel its job and all its children. Just about what is needed.
Log statements confirm this too:
WorkRequest - state observation - start
WorkRequest - ENQUEUED
WorkRequest - RUNNING
WorkRequest - SUCCEEDED
WorkRequest - Work finished
WorkRequest - state observation - endlogs
The full method:
fun startTodoWork() {
viewModelScope.launch {
val oneTimeWorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
.addTag("myTag")
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
workManager.enqueueUniqueWork(
"uniqueWorkName",
ExistingWorkPolicy.REPLACE,
oneTimeWorkRequest
)
supervisorScope {
launch {
Log.d("TAG", "WorkRequest - state observation - start")
workManager.getWorkInfoByIdLiveData(oneTimeWorkRequest.id).asFlow().collect {
Log.d("TAG", "WorkRequest - ${it?.state?.name!!}")
if (it.state.isFinished) {
Log.d("TAG", "WorkRequest - Work finished")
cancel() // cancel the supervisorScope, it is now redundant
}
}
}
}.invokeOnCompletion {
Log.d("TAG", "WorkRequest - state observation - end")
}
}
}full.kt