Android WorkManager: Cannot get output data from PeriodicWorkRequest
Asked Answered
X

2

22

For some reasons I cannot get output data from PeriodicWorkRequest of Android WorkManager. The worker runs periodically as expected, it just doesn't return any data.

My MainActivity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    schedulePeriodicRequests();
}

public void schedulePeriodicRequests() {
    PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(ServerRequestsWorker.class, 15, TimeUnit.MINUTES)
            .build();

    WorkManager workManager = WorkManager.getInstance(MainActivity.this);
    workManager.enqueue(workRequest);
    workManager.getWorkInfoByIdLiveData(workRequest.getId())
            .observe(this, new Observer<WorkInfo>() {
                @Override
                public void onChanged(@Nullable WorkInfo workInfo) {
                    if (workInfo != null) {
                        Log.d(LOG_TAG, "WorkInfo received: state: " + workInfo.getState());
                        String message = workInfo.getOutputData().getString(ServerRequestsWorker.KEY_MESSAGE);
                        Log.d(LOG_TAG, "message: " + message);
                    }
                }
            });
}

My ServerRequestsWorker:

public static final String KEY_MESSAGE = "message";

@NonNull
@Override
public Result doWork() {
    Log.d(LOG_TAG, "Worker works");

    Data outputData = new Data.Builder()
            .putString(KEY_MESSAGE, "This is output message")
            .build();

    return Result.success(outputData);
}

The value from workInfo.getOutputData().getString is always null. Here's what I get in the log:

MainActivity: WorkInfo received: state: ENQUEUED
MainActivity: message: null
ServerRequestsWorker: Worker works
WM-WorkerWrapper: Worker result SUCCESS for Work [ id=5f2beba8-c8bf-4f07-b4ee-e876e95d3cdb, tags={ com.anshmidt.pricemonitor.ServerRequestsWorker } ]
MainActivity: WorkInfo received: state: RUNNING
MainActivity: message: null
MainActivity: WorkInfo received: state: ENQUEUED
MainActivity: message: null

It's interesting that getting output data from OneTimeWorkRequest is working fine. If I switch from PeriodicWorkRequest to OneTimeWorkRequest:

    OneTimeWorkRequest serverScraperWorkRequest = new OneTimeWorkRequest.Builder(ServerRequestsWorker.class)
            .build();

    WorkManager workManager = WorkManager.getInstance(MainActivity.this);
    workManager.enqueue(serverScraperWorkRequest);
    workManager.getWorkInfoByIdLiveData(serverScraperWorkRequest.getId())
            .observe(this, new Observer<WorkInfo>() {
                @Override
                public void onChanged(@Nullable WorkInfo workInfo) {
                    if (workInfo != null) {
                        Log.d(LOG_TAG, "WorkInfo received: state: " + workInfo.getState());
                        String message = workInfo.getOutputData().getString(ServerRequestsWorker.KEY_MESSAGE);
                        Log.d(LOG_TAG, "message: " + message);
                    }
                }
            });

, then I successfully receive the value from output data:

MainActivity: message: This is output message

I've tried enqueueing unique work and enqueueing by tag, but no luck. Have tried WorkManager 2.2.0 and 1.x, result is the same.

Am I missing something? Is it even possible to get output data from PeriodicWorkRequest? What do I wrong?

Ximenez answered 8/9, 2019 at 20:17 Comment(1)
WorkManager.getInstance().enqueueUniquePeriodicWork("Weather Worker", ExistingPeriodicWorkPolicy.REPLACE, work) witll solve ur issue. Use REPLACE for periodic workCymbiform
C
25

As per the WorkInfo documentation:

Note that output is only available for the terminal states (WorkInfo.State.SUCCEEDED and WorkInfo.State.FAILED).

For Periodic work, the same ID is reused for each run, meaning that the work never gets to SUCCEEDED - instead, the work transitions immediately back to ENQUEUED, waiting for the next periodic run. Therefore, what you're experiencing seems to be the expected behavior.

As you've seen, using one time work does not have this behavior, since the work actually gets to SUCCEEDED and each subsequent run (if your one time work were to reschedule the same type work) would have a new ID. The other alternative is to not use output data, but instead store the result of your periodic work in your own database.

Calisa answered 8/9, 2019 at 20:51 Comment(1)
Life-saving answer 10/10Monition
I
5

The other alternative is Observing intermediate Worker progress

in your ServerRequestsWorker :

        val outputProgress = workDataOf(KEY_MESSAGE to "This is progress message")
        setProgress(outputProgress)

then in your MainActivity :

workManager.getWorkInfoByIdLiveData(workRequest.getId())
        .observe(this, new Observer<WorkInfo>() {
            @Override
            public void onChanged(@Nullable WorkInfo workInfo) {
                if (workInfo != null) {
                    Log.d(LOG_TAG, "WorkInfo received: state: " + workInfo.getState());
                    String message = workInfo.getProgress().getString(ServerRequestsWorker.KEY_MESSAGE);
                    Log.d(LOG_TAG, "message: " + message);
                }
            }
        });
Incipient answered 16/2, 2022 at 1:43 Comment(1)
I don't think it will work for periodic requests. You will get null all the time.Candra

© 2022 - 2024 — McMap. All rights reserved.