androidandroid-workmanager

Canceling Unnamed, Non-Unique Periodic WorkRequests in Android WorkManager


In a previous iteration of our application, we implemented a periodic task using WorkManager as follows:

WorkManager.getInstance(context).enqueue(
    new PeriodicWorkRequest.Builder(OurClassName.class, 8, TimeUnit.HOURS)
        .setConstraints(constraints)
        .setInputData(OurClassName.getParameterBundle())
        .build()
);

This code snippet schedules a job that executes every 8 hours.

However, we've encountered an issue where these tasks cannot be canceled since they were not assigned a unique 'name' or 'tag'.

Complicating matters, due to a bug, this scheduling code was executed every time the app launched, resulting in a significant accumulation of identical, scheduled jobs.

Despite attempting to use both WorkManager and JobScheduler's cancelAll methods as a broad-stroke solution, the jobs persist.

How can we effectively cancel these periodically scheduled tasks, especially considering they lack unique identifiers?


Solution

  • We've encountered an issue where these tasks cannot be canceled since they were not assigned a unique 'name' or 'tag'.

    The WorkRequest created by the .build() function can be used to fetch the id to manage its operation via WorkManager instance. Example:

    val periodicWorker = new PeriodicWorkRequest.Builder(OurClassName.class, 8, TimeUnit.HOURS)
            .setConstraints(constraints)
            .setInputData(OurClassName.getParameterBundle())
            .build()
    
    val workId = periodicWorker.id;
    

    Complicating matters, due to a bug, this scheduling code was executed every time the app launched, resulting in a significant accumulation of identical, scheduled jobs.

    This is expected due to the use of enqueue. Using enqueueUniquePeriodicWork would work as expected.

    For cancellations, see: https://developer.android.com/develop/background-work/background-tasks/persistent/how-to/manage-work#cancelling


    Assuming you need to cancel all the previous WorkRequests (say on a new app update), you can use - WorkManager.getInstance(context).cancelAllWork() or WorkManager.getInstance(context).cancelAllWorkById(workId) if you have the IDs & then register the new WorkRequests via enqueueUniquePeriodicWork.

    Disclaimer from the docs:

    Cancels all unfinished work. Use this method with extreme caution! By invoking it, you will potentially affect other modules or libraries in your codebase. It is strongly recommended that you use one of the other cancellation methods at your disposal.