Search code examples
androidandroid-workmanager

WorkManager not being replaced using ExistingPeriodicWorkPolicy.REPLACE


Calling ExistingPeriodicWorkPolicy.REPLACE just starts another workManager it doesn't replace the other one, multiple workManagers are running when triggered not replaced

val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build()

    val workRequest = PeriodicWorkRequestBuilder<SongsWorker>(1, TimeUnit.DAYS)
            .addTag(TAG)
            .setConstraints(constraints)
            .build()

    WorkManager.getInstance(mContext).enqueueUniquePeriodicWork(
        TAG, ExistingPeriodicWorkPolicy.REPLACE, workRequest)

The log suggests the work manager is at least asking to be cancelled, but the execution continues

I/WM-WorkerWrapper: Work [ id=6ed5487e-5d7b-4db5-a4c5-c22c562567e5, tags={ 
workerManagers.songs.SongsWorkerManager$SongsWorker } ] was cancelled
java.util.concurrent.CancellationException: Task was cancelled.
    at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184)
    at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514)
    at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
    at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:300)
    at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:923)

I have attached a listener to the work manager and the log is

2021-04-30 20:40:54.318 17868-17868 Fragment: ID = 9f8b3165-fc75-4f9a-ba39-41c2dc6a17b3
2021-04-30 20:40:54.408 17868-17868 Fragment: ID = 9f8b3165-fc75-4f9a-ba39-41c2dc6a17b3
2021-04-30 20:40:54.427 17868-17868 Fragment: ID = 9f8b3165-fc75-4f9a-ba39-41c2dc6a17b3

The listener is:

val instance = WorkManager.getInstance(requireContext())
  instance.getWorkInfosForUniqueWorkLiveData(SongsWorkerManager.TAG)
        .observe(viewLifecycleOwner) { workInfo ->
            workInfo.forEach {
                Log.d(TAG, "ID = ${it.id}")
            }
        }

After triggering the work manager 3 times, 3 identical work managers are running rather then being replaced.


Solution

  • If anyone else is having trouble stopping a work manager with ExistingPeriodicWorkPolicy.REPLACE, call

    if (isStopped) return Result.success()
    

    inside doWork() and you will get the behaviour you expect.

    Thanks to

    WorkManager.getInstance().cancelAllWorkByTag() not stopping the periodic job

    ""One way to do this is to put a few checks in your doWork method to check if the worker has been cancelled, by calling isStopped(). If isStopped is true, return from the method with a Result instead of continuing with the rest of the work.""

    and

    How to make sure that WorkManager cancels my Worker?