Kakashi
Kakashi

Reputation: 3549

workstatus observer always in enqueued state

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

Answers (4)

M.Ed
M.Ed

Reputation: 1328

As others have said, PeriodicWorkRequests 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 PeriodicWorkRequests 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

KKM
KKM

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 :

  1. The actual Worker:
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();
    }
}

  1. Your activity that observes this worker's info:
//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

Rahul
Rahul

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

nst0022
nst0022

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

Related Questions