For periodic background tasks, I see that JobScheduler
is often used. Alternatively, there're also JobService
and AlarmManager
for slightly (?) different use cases. But why not just spin up a new Runnable
? What are the downsides of using a Runnable
for background tasks? Does Runnable
use more resources when it's idle?
Runnable
is an interface that does nothing on it's own other than provide a single method named run
. Perhaps you are wondering about how HandlerThread
, Thread
, AsyncTask
, ExecutorService
are used vs JobScheduler
, IntentService
and AlarmManager
?
Here is an Android threading cheatsheet:
Runnable
: an interface that does nothing on its own but is used when interacting with many other threading related classesThread
: most elemental way to run code off the main thread of a process.AsyncTask
: basic Android-centric way to run code off the main thread, there is a single thread devoted to all AsyncTask instances so only one can ever run at a time in your processHandlerThread
: convenient way to send messages (possibly with a delay) between your main thread and another threadExecutorService
: powerful thread pool that allows you to take advantage of multiple CPU coresService
(Android): an android component which does not have a user interface but whose methods still run on the main threadIntentService
: an android Service subclass you may extend which contains a single background thread on which work without an associated Activity can be doneAlarmManager
: a mechanism provided by the Android system to start Android components at a particular time, but which forgets everything upon rebootJobScheduler
: a Lollipop and above mechanism provided by Android system to start android Services based on a description of the work to be done and which can optionally retain configuration across reboots (prefer WorkManager now)WorkManager
: an Android architecture component (library provided by Google which runs on many versions of Android) which works similarly to JobScheduler but additionally allows multiple jobs to be coordinatedHow Android OS manages processes and threads:
It is important to understand how the Android OS manages applications when choosing a threading mechanism. The Android OS sees applications and components within applications (Activity
, Service
, BroadcastReciever
and ContentProvider
). The high level Android OS is not aware of the threads inside of an application.
Unlike applications on a desktop computer the installed application processes in Android OS have much more fuzzy lifecycle. For example if you start the calculator app Android creates a linux process for it. If you leave the calculator it generally does not kill the calculator process immediately. If you start using many other applications and do not return to the calculator for a long time it may eventually decide to reclaim the memory used by the calculator process and end that process. Even if the process lives the user might let the phone go to sleep and the CPU will stop execution of all threads in all processes until the CPU wakes up again. Wakelocks can prevent CPU sleep. Mechanisms such as WorkManager
can take care of wakelocks for you.
What this means in practice is that you can spin threads off from an Activity
they have a life of their own that can go on as long as the process is alive, threads do not get paused or stopped by the Android OS even though the Activity
may be receiving these lifecycle callbacks. However when Android decides to end your process all your threads die too. The only way for you as an app developer to inform Android that it should not kill your process is to create a Service
and perhaps even make it a foreground Service
so that Android knows something important is going on in your app, or use WorkManager
since Android is aware of that (under the hood it's probably a Service
...). When using a Service
you still need to spin off a thread of some kind to do your work because the Service
function execute on the main thread of your process, unless you are receiving messages via IPC binder calls, those run on a pool of 16 binder threads, the same goes for ContentProvider
methods if they are invoked via IPC and not locally.
Here are a few questions to help you decide what to use:
Consider HandlerThread
, AsyncTask
, or ExecutorService
Consider Service
paired with a HandlerThread
or something similar.
Consider WorkManager
, or AlarmManager
with IntentService
Consider WorkManager
As always it is best to get this kind of information straight from the source. For example https://developer.android.com/topic/libraries/architecture/workmanager Google says:
Note: WorkManager is intended for tasks that require a guarantee that the system will run them even if the app exits, like uploading app data to a server. It is not intended for in-process background work that can safely be terminated if the app process goes away; for situations like that, we recommend using ThreadPools.
For more tips like that read the javadocs and guides on https://developer.android.com/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With