Reputation: 3549
I am trying to observe my workers
but they are always in queued
state or sometime it's RUNNING
but never SUCCEED
or FAILED
.
is workStatus.state
from return in doWork()
or it's different?
this is my worker script:
package com.mockie.daikokuten.sync.workers
import androidx.work.Worker
class TestWorker:Worker()
{
override fun doWork():Worker.Result
{
return Worker.Result.SUCCESS
}
}
this is script to observe the workers :
val test = PeriodicWorkRequest.Builder(
TestWorker::class.java,
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
TimeUnit.MILLISECONDS)
.addTag("test_worker")
.build()
WorkManager.getInstance()?.enqueueUniquePeriodicWork("test_worker", ExistingPeriodicWorkPolicy.KEEP, test)
WorkManager.getInstance()!!.getStatusesByTag("test_worker")
.observe(this, Observer { workStatus ->
if (workStatus != null)
{
for(ws in workStatus)
{
Log.d(":dump2 id ", ws.id.toString())
Log.d(":dump2 tag", ws.tags.toString())
Log.d(":dump2 state", ws.state.toString())
}
}
})
this is the result in Logcat:
07-23 17:12:30.901 29740-29740/com.mockie.daikokuten D/:dump2 id: 5c6297f7-11d8-4f2f-a327-773672a7435c
07-23 17:12:30.901 29740-29740/com.mockie.daikokuten D/:dump2 tag: [test_worker, com.mockie.daikokuten.sync.workers.TestWorker]
07-23 17:12:30.901 29740-29740/com.mockie.daikokuten D/:dump2 state: ENQUEUED
Upvotes: 4
Views: 4089
Reputation: 1328
As others have said, PeriodicWorkRequest
s indeed never reach SUCCEEDED
state, so you'll never be able to observe whatever value you return within your Result.success(yourData).
But all hope is not lost!
You can actually observe data in PeriodicWorkRequest
s without any hacks like setting up static observables or writing/reading the data to/from shared prefs or a local database.
In doWork, we set data via setProgress, and add a non-blocking delay with Coroutine's delay() function before we return a Result:
override suspend fun doWork(): Result {
// do long running work, like waiting for the result of an async api call
val outputData: Data = Data.Builder()
.putString("asyncString", asyncString)
.build()
setProgress(outputData)
delay(1000)
Result.success()
}
Then you can observe the LiveData (or Kotlin's Flow) retrieved by getWorkInfoByIdLiveData and read the the data you set in the Worker's setProgress with WorkInfo's getProgress():
val workRequest = PeriodicWorkRequestBuilder<MyWorker>(1, TimeUnit.HOURS)
.setInputData(workerData)
.build()
WorkManager.getInstance(context).enqueue(workRequest)
val workInfo = WorkManager.getInstance(context).getWorkInfoByIdLiveData(workRequest.id).asFlow()
scope.launch {
updateWorkInfo.collect { workInfo ->
workInfo.progress.getString("asyncString", "")
}
}
The 1 second delay we set in doWork() before we returned Result.success() is necessary because when Result.success() is called, the work immediately finishes and its state becomes ENQUEUED
; you won't have enough time to observe any on-going work.
Read more: https://developer.android.com/guide/background/persistent/how-to/observe
Upvotes: 1
Reputation: 744
This is for anyone who is having trouble getting their output data from periodic work. It's more like a hack. In your Worker, just define a static mutable Live Data. At the place where you observe your work's state, observe this live data when your state turns to "RUNNING".
Here's a template :
public class SomeWorker extends Worker{
//This live data can be of any type. I'm setting Boolean
Public static MutableLiveData<Boolean> outputObservable = new MutableLiveData();
private boolean output_boolean;
try{
//Do you work here post your result to the live data
output_boolean = SomeTaskThatReturnsABoolean();
outputObservable.postValue(output_boolean);
return Result.Success();
}catch(Exception e){
e.printStackTrace();
outputObservable.postValue(!output_boolean);
return Result.Failure();
}
}
//In YourActivity class inside OnCreate
mWorkManager.getWorkInfoForUniqueWorkLiveData(YOUR_TAG).observe (this,
new Observer<List<WorkInfo>>(){
@Override
public void onChanged(@Nullable List<WorkInfo> workInfos) {
if(workInfos!=null && (!(workInfos.isEmpty()))) {
WorkInfo info = workInfos.get(0);
switch(info.getState()){
case ENQUEUED:
break;
case RUNNING:
SomeWorker.outputObservable.observe(YourActivity.this,
new Observer<Boolean>(){
@Override
public void onChanged(@Nullable Boolean aBoolean) {
//EDIT: Remove the observer of the worker otherwise
//before execution of your below code, the observation might switch
mWorkManager.getWorkInfoForUniqueWorkLiveData(YOUR_TAG).removeObservers(YourActivity.this);
if(aBoolean)
//Do whatever you have to if it's true
else
//Do whatever you have to if it's false
}
}
);
}
}
}
}
);
In this way you can observe your results when the state of the work is under running, before it gets switched back to enqueued.
Upvotes: 1
Reputation: 21134
The above answer is correct. For PeriodicWork you should see:
ENQUEUED -> RUNNING -> ENQUEUED
However, there is a bug in alpha04
which causes PeriodicWork
to not run on API >= 23. This will be fixed in alpha05
. For more info take a look at https://issuetracker.google.com/issues/111195153.
IMPORTANT: As of a couple of days ago: alpha05
has shipped. This bug is fixed.
Upvotes: 0
Reputation: 469
For your periodic work request you should see
ENQUEUED - RUNNING - ENQUEUED
where the latter ENQUEUED is the state of the next work request.
You might get very briefly a SUCCEEDED between RUNNING and ENQUEUED, but I have never seen that.
For a onetime work request you see
ENQUEUED - RUNNING - SUCCEEDED
or whatever you return in doWork().
(Android 8.1 API 27, 1.0.0-alpha04)
Upvotes: 5