Android WorkManager doesn't trigger one of the two scheduled workers

浪子不回头ぞ 提交于 2020-04-11 04:04:40

问题


I have two periodic workers scheduled in my app where one worker repeats after 24 hours and another in 15 minutes.

Initially on fresh install things work as expected, but after some days I got an issue on 2 devices(out of 5). The 24 hour worker is triggered properly but the 15 minute one isn't triggered at all. I have been monitoring this for 24 hours now.

I viewed the databse of workmanager via Stetho and saw some entries for 24-hour worker and 0 entries for 15 minute worker. I'm looking in the WorkSpec table.

I debugged via Android studio and after querying WorkManager using getWorkInfosByTag() I got a list of 80 objects for the 15-minute worker where 79 were in CANCELED state and one was in ENQUEUED state.

So apparently, canceled workers are not added to the DB?

I did not find any document from Google which explains the scenarios in which worker is canceled.

I am using 1.0.0-beta03 version of the work runtime. Also, I am not killing the app or doing anything funny. The app is running in the background and not being killed. Devices are Mi A2 (Android 9), Redmi Note 4(Android 7).

I need to understand why is the worker being canceled and is there any better way to debug this? Any pointers will be helpful and upvoted!

Thanks.

Edit1: Posting the code to schedule both workers.

24-hour periodic worker:

public static synchronized void scheduleWork() {
    checkPreviousWorkerStatus();
    if (isWorking()) {
        Log.i("AppDataCleanupWorker", "Did not schedule data cleanup work; already running.");
        return;
    }

    if (lastWorkId != null) {
        WorkManager.getInstance().cancelAllWorkByTag("AppDataCleanupWorker");
        lastWorkId = null;
    }

    Constraints constraints = new Constraints.Builder()
            .setRequiresCharging(true)
            .build();

    PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
            .Builder(AppDataCleanupWorker.class, 24, TimeUnit.HOURS)
            .addTag("AppDataCleanupWorker")
            .setConstraints(constraints);

    PeriodicWorkRequest workRequest = builder.build();
    lastWorkId = workRequest.getId();
    WorkManager.getInstance().enqueue(workRequest);

    List<WorkInfo> workInfos = WorkManager.getInstance()
            .getWorkInfosByTagLiveData("AppDataCleanupWorker")
            .getValue();
    if (workInfos != null && workInfos.size() > 1) {
        throw new RuntimeException("Multiple workers scheduled. Only one schedule is expected.");
    }
}

15-minute periodic worker:

public static synchronized void scheduleWork() {
    checkPreviousWorkerStatus();
    if (isWorking) {
        Log.i("ImageUploadWorker", "Did not schedule image upload work; already running.");
        return;
    }

    if (lastWorkId != null) {
        WorkManager.getInstance().cancelAllWorkByTag("ImageUploadWorker");
        lastWorkId = null;
    }

    Constraints constraints = new Constraints.Builder()
            .setRequiresBatteryNotLow(true)
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build();
    PeriodicWorkRequest.Builder builder =
            new PeriodicWorkRequest.Builder(ImageUploadWorker.class, 15,
                    TimeUnit.MINUTES)
                    .addTag("ImageUploadWorker")
                    .setConstraints(constraints);
    PeriodicWorkRequest workRequest = builder.build();
    lastWorkId = workRequest.getId();
    WorkManager.getInstance().enqueue(workRequest);

    List<WorkInfo> workInfos = WorkManager.getInstance()
            .getWorkInfosByTagLiveData("ImageUploadWorker").getValue();
    if (workInfos != null && workInfos.size() > 1) {
        throw new RuntimeException("Multiple workers scheduled. Only one schedule is expected.");
    }
}

Note: The device is connected to the Internet & network speed is pretty good.


回答1:


SOLVED: Worker not being triggered by WorkManager

Resolved the issue after some debugging. Posting here in case someone runs into the same issue.

So, I was canceling and enqueuing workers again and again. So lets say a worker is scheduled for 11.15 AM today, then I cancel and enqueue again, the 11.15 AM slot was not being given to the newly enqueued worker.

Instead, When the 11.15 AM slot is utilised, the work manager just checks that the scheduled worker was canceled and does not trigger the newly enqueued worker.

This was the behaviour on 3 out of 5 devices we tested on. On 2 devices the newly enqueued worker was properly being triggered.

Now the solution:

  1. Remove all code to schedule your workers.

  2. In the onCreate() of your application, first invoke pruneWork() on WorkManager to remove all piled up cancelled worker schedules. Remember the method returns Operation which will help you check the completion of removal. Before calling pruneWork() you might also call cancelAllWorkByTag() for all your workers to clean up any and all the pending schedules. This method also returns an Operation.

  3. After the work manager schedules are cleared, you can now schedule your PeriodicWorkRequest the way you want. I used enqueueUniquePeriodicWork() to make sure only one instance of worker is running at a time.

Now, my worker is being triggered every 15 minutes properly.

Note that as and when your device sleeps and goes into doze mode, this 15 minute duration will increase.

You can check the work manager database using Stetho library. The table name is WorkSpec where you'll find all the schedules for your workers. And you can stop app execution at some breakpoint and use getWorkInfosByTag() on WorkManager to get a list of schedules and their current status.




回答2:


You're doing a few things that are incorrect.

  1. You're using LiveData and calling getValue() on it without adding an Observer. This won't give you what you're looking for - the LiveData never starts tracking the values that you want. Please check out proper LiveData usage here: https://developer.android.com/topic/libraries/architecture/livedata

  2. If you only want one particular copy of a type of work, you should use enqueueUniqueWork instead of enqueue.

  3. Unless you found yourself in an extremely bad situation where you actually need to remove old workers, I would advise you not to call pruneWork(). Please see the documentation: https://developer.android.com/reference/androidx/work/WorkManager#pruneWork()



来源:https://stackoverflow.com/questions/54456396/android-workmanager-doesnt-trigger-one-of-the-two-scheduled-workers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!