It's mentioned in WorkManager documentation that cancelling a Worker is best-effort
WorkManager makes its best effort to cancel the task, but this is
inherently uncertain--the task may already be running or finished when
you attempt to cancel it
What if i have a use case that it's mandatory that the Worker gets cancelled upon calling one of the cancelling methods?
As you wrote WorkManager can only try with a best-effort to cancel a work. In particular, if a task is scheduled to run, and you cancel it, WorkManager will remove it from the schedule.
However, if the tasks it's already running, WorkManager cannot safely interrupt it. The best option is that you write your Worker class taking care of an external cancellation. This has been covered in the Working with WorkManager talk (around minute 15) recorded at the Android Developer Summit 2018.
To be a good citizen you can pool WorkManager using the method: ListenableWorker.isStopped(). You can combine this with the onStopped callback to cleanup your code when you or the OS request to stop the task.
Related
Does the Work manager will stop the work after the constraints become not satisfied while the work is processing.
For example, work requires charger connected constraint, after connecting the charger the work starts, and then the charger gets disconnected, does the Work manager will stop the work, as it's not satisfying the constraints anymore
If a constraints is not satisfied anymore during the execution of a worker, WorkManager will signal its stoppage.
Keep in mind that stoppages are cooperative in WorkManager, so your Worker will need to implement the onStopped() callback and it can use the isStopped() method while executing long running loops/computation.
From the doc:
You should cooperatively abort any work you had in progress and release any resources your Worker is holding onto. For example, you should close open handles to databases and files at this point. There are two mechanisms at your disposal to understand when your Worker is stopping.
Alsoi from the doc:
Note: WorkManager ignores the Result set by a Worker that has received the onStop signal, because the Worker is already considered stopped.
If you are using CoroutineWorkers, these are going to handle stoppages automatically in the defined scope.
From WorkManager's threading guide:
CoroutineWorkers handle stoppages automatically by cancelling the coroutine and propagating the cancellation signals. You don't need to do anything special to handle work stoppages.
I was reading Guide To Background Tasks, it's well organized and understandable except a few concepts.
Can anyone differentiate between Deferred and Exact background Tasks with some realtime android examples?
Deferred tasks
Every task that is not directly connected to a user interaction and can run at any time in the future can be deferred. The recommended solution for deferred tasks is WorkManager.
WorkManager makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or the device restarts. See the documentation for WorkManager to learn how to schedule these types of tasks.
Exact tasks
A task that needs to be executed at an exact point in time can use AlarmManager.
To learn more about AlarmManager, see Schedule repeating alarms.
Recently, started using the WorkManager library.
1)If I cancel a tagged work using it's tag, does it enter the CANCELLED state?
2)What are other scenarios can make it go to CANCELLED state?
So it seems like only a manual cancellation of a worker results in it being in the CANCELLED state (or by the system).
It does not matter which Result is returned in doWork().
I think it's the same as when onStopped() is called:
https://developer.android.com/reference/androidx/work/ListenableWorker#onstopped
This method is invoked when this Worker has been told to stop. This could happen due to an explicit cancellation signal by the user, or because the system has decided to preempt the task. In these cases, the results of the work will be ignored by WorkManager.
The documentation for GcmNetworkManager::cancelTask
https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager"
says
Cancel a task, specified by tag. Note that a cancel will have no
effect on an in-flight task.
What's an "in-flight" task ?
According to the documentation, the GcmNetworkManager collects various requests and executes them batch-wise (in the intention to minimize the times, the network system is used, in order to save battery).
To my understanding, "in-flight" then means tasks, that are really already started, i.e. where the syncing is already in progress. So basically, you can only cancel tasks that have not yet started.
I'm trying to implement a PeriodicTask with the GcmNetworkManager API (existing since Google Play Services 7.5).
My task is scheduled as soon as my app starts and will check the content of a Queue of objects in order to send them as batches to my server.
If the queue is empty, the method onRunTask() will do pretty much nothing (it will check the queue and return GcmNetworkManager.RESULT_SUCCESS).
I have put some logs in the implementation and noticed that the PeriodicTask keeps running forever, even after my app is in background or removed from memory.
This made me worry about my users' battery. Even though I won't perform any heavy task or HTTP request, the process is started periodically without real need.
At first, I thought GcmNetworkManager would be smart to exponentially back-off my Task until it stopped (or maybe I'm doing something wrong that prevents that), but, as my logs showed, that did not happen.
Afterwards, I have tried using cancelTask() and cancelAll() but those do not work if called from within the Task's onRunTask() method itself. Even calling stopSelf() is not a good idea since GcmNetworkManager is the one responsible for the Service lifecycle so I do not want to get in the way.
The difficulty of actually finishing the task made me think if that is the right approach (maybe I should just let the Task live forever?).
How can I use PeriodicTask properly while not draining the user's battery?
First of all, do you really need periodic task execution? It sounds like you can register OneoffTask with updateCurrent whenever you update your Queue. In case of upload failure, you can use RESULT_RESCHEDULE to retry later (and Google Play service will employ exponential back off strategy to decide when to retry).
I don't know your requirement, so you may really need PeriodicTask. If so, you don't have to worry too much about battery. The idea of GcmNetworkManager is that, you let Google Play service handle task execution, so it can execute multiple tasks together.
Phone will consume battery when it changes its state from inactive to active (see e.g., https://www.youtube.com/watch?v=-3ry8PxcJJA) so as long as your job is executed in batch with other tasks and finishes your job immediately, you don't waste much power. You can configure executionWindow to encourage batching.