Android WorkManager api for running daily task in Background
Asked Answered
B

6

21

I need to call one API daily in the background even if the app is closed. I have seen about WorkManager API. For my scenario, I tried PeriodicWorkRequest but unfortunately, it's not working as my expected result. What I did is I used this code in the Application class

 PeriodicWorkRequest.Builder myWorkBuilder =
                new PeriodicWorkRequest.Builder(MyWorker.class, 24,
                        TimeUnit.HOURS);

        PeriodicWorkRequest myWork = myWorkBuilder.build();
        WorkManager.getInstance().enqueue(myWork);

But it's running repeatedly for 11 times when the app is open for the first time after that, it's not running after 24 hrs. Please, anyone, help me to solve.

Bandage answered 18/5, 2018 at 16:35 Comment(0)
S
41

If you want to make sure your PeriodicWorkRequest is not created multiple times you can use the WorkManager.enqueueUniquePeriodicWork method to schedule your worker:

This method allows you to enqueue a uniquely-named PeriodicWorkRequest, where only one PeriodicWorkRequest of a particular name can be active at a time. For example, you may only want one sync operation to be active. If there is one pending, you can choose to let it run or replace it with your new work.


For example:

PeriodicWorkRequest.Builder myWorkBuilder =
            new PeriodicWorkRequest.Builder(MyWorker.class, 24, TimeUnit.HOURS);

PeriodicWorkRequest myWork = myWorkBuilder.build();
WorkManager.getInstance()
    .enqueueUniquePeriodicWork("jobTag", ExistingPeriodicWorkPolicy.KEEP, myWork);
Spheno answered 28/6, 2018 at 12:50 Comment(6)
is there a similar option available for onetimerequest as well? Sometimes same work is called twice in parallel. how to stop this?Pout
@Pout have you tried beginUniqueWork(...)?Spheno
Yes I tried but we need to use Workcontinuation object. I dont know if that option is costlier one. Any idea?Pout
according to the best practices where in the app should we configure the job?Toein
The above code snippet to initiate a PeriodicWorkRequest in a device (OnePlus 4T) having Android Pie (9), not working, WorkManager is not enqueuing the Worker. As I have also asked for help on stackoverflow here: #56697605Simmers
@whlk, I have tried this above method for my daily background notification sending. but, after run, that time only, getting notification. but, when we change date in mobile settings, its not triggering notification. i just turned off network datetime. just used daily changin date in calendar. can you ping latest dependency veriosn in work managerRomola
L
14

I think there are three problems.

1) You’re creating a new periodic work every time you enqueue myWork to the WorkManager Instance.

Try it, the logic in the doWork() method of your MyWorker.class runs once the first time, runs twice the second time. You most likely added 11 works to Work Manager and this is why it ran 11 times, the last time you checked. If you create new works and add it to the work manager then the number of times myWork runs increases.

Similar to Job Scheduler, you have to check if the Work exists or not before you add it to the Work Manager.

Sample Code:

final WorkManager workManager = WorkManager.getInstance();
final LiveData<List<WorkStatus>> statusesByTag = workManager
        .getStatusesByTag(TAG_PERIODIC_WORK_REQUEST);

    statusesByTag.observe(this, workStatuses -> {
    if (workStatuses == null || workStatuses.size() == 0) {
        Log.d(TAG, "Queuing the Periodic Work");
        // Create a periodic request
        final PeriodicWorkRequest periodicWorkRequest =
                new PeriodicWorkRequest.Builder(SyncWorker.class, 30, TimeUnit.MINUTES)
                        .addTag(TAG_PERIODIC_WORK_REQUEST)
                        .build();

        // Queue the work
        workManager.enqueue(periodicWorkRequest);
    } else {
        Log.d(TAG, "Work Status Size: " + workStatuses.size());
        for (int i = 0; i < workStatuses.size(); i++) {
            Log.d(TAG, "Work Status Id: " + workStatuses.get(i).getId());
            Log.d(TAG, "Work Status State: " + workStatuses.get(i).getState());
        }
        Log.d(TAG, "Periodic Work already exists");
    }
});

In the above sample, I'm using a unique tag TAG_PERIODIC_WORK_REQUEST to identify my periodic work and checking if it exists or not before creating it.

2) Your work may not be running when the app is killed.

What is the brand, you're testing on? Is it Xiaomi? Have you tested it on multiple other brands and ended up with the same result?

Was it in Doze mode? And how are you validating that the work is not running when you set 24 hours time?

Work Manager provides backward compatibility but still, you need to handle the device specific logic. On Xiaomi devices, similar to Job Scheduler (or Firebase Job Dispatcher or Alarm), the periodic work stops when the app is killed.

3) I just think the PeriodicWorkRequest provided by WorkManager is buggy.

I have been testing it since the start of the previous week on multiple devices. I created a work when the app was launched the first time and didn't open it for three days. It ran once the first time, two times when the second sync was triggered and in between, it increased to 13 times, dropped to 1 time, 4 times etc.,.

In another test, I created a work with the below code during the first install and removed the code from the second install. During this test, Even if the work successfully completed, the work ran every time, the app is opened after killing it.

final PeriodicWorkRequest periodicWorkRequest =
            new PeriodicWorkRequest.Builder(SyncWorker.class, 30, TimeUnit.MINUTES)
                    .addTag("periodic-work-request")
                    .build();

// Queue the work
WorkManager.getInstance().enqueue(periodicWorkRequest);

I understand that since it is still in alpha. I don't think you should be using it in production.

Leblanc answered 21/5, 2018 at 15:55 Comment(5)
Thanks Srikar.I am using Xiaomi device and for testing i set it for 20 minutes.its not running correctly.hopefully i go back to job scheduler again.Funicular
On Xiaomi, background jobs only run if set Battery Saver option to None.Leblanc
Don't think JobScheduler will run either. If does, do let me know.Leblanc
@SrikarReddy Is there any hack for Xiaomi devices ?Bruyn
@AbhishekBatra Did you got any solution for Red mi phone apart from the "Auto Start" or "Battery Saver disable"..Krahling
R
2

If you add a tag to the PeriodicWorkRequestBuilder, and then call WorkManager.getInstance().cancelAllWorkByTag(REQUEST_TAG) before you enqueue the periodic request, that will keep the dupes from happening:

Android Workmanager PeriodicWorkRequest is not unique

Rms answered 24/5, 2018 at 3:34 Comment(0)
F
1

Starting from alpha03 you can schedule a unique periodic work: https://developer.android.com/jetpack/docs/release-notes

WorkManager.enqueueUniquePeriodicWork(String uniqueWorkName, ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy, PeriodicWorkRequest periodicWork) allows you to enqueue a unique PeriodicWorkRequest

So it is quite simpler to achieve what you want now.

Finley answered 27/6, 2018 at 15:25 Comment(0)
R
0

There was issue in alpha 01 which:

Fixed an issue which caused Workers to be rescheduled on Application.onCreate().

Use latest version of WorkManager i.e. 1.0.0-alpha02. Check release notes for more info

Riplex answered 3/6, 2018 at 3:27 Comment(3)
I am using 1.0.0-alpha02 but still having same issue.Eulalie
same here. More and more jobs created each app start.Sacristan
Looks like issue is still not fixedRiplex
K
0

Use WorkManager version 1.0.0-alpha04. You can check release notes here

Also, refer to this PeriodicWorkRequest GitHub demo which update day counter once in a day (every 24 hours) during the maintenance window. It executes doWork() method, whether the application is open or closed.

WorkManager is still in alpha mode so it will work completely for all devices once they release the final version.

Kurus answered 2/7, 2018 at 12:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.