Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Job Scheduler vs Runnable: Downsides?

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?

like image 759
John M. Avatar asked Nov 28 '22 22:11

John M.


1 Answers

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 classes
  • Thread: 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 process
  • HandlerThread: convenient way to send messages (possibly with a delay) between your main thread and another thread
  • ExecutorService: powerful thread pool that allows you to take advantage of multiple CPU cores
  • Service (Android): an android component which does not have a user interface but whose methods still run on the main thread
  • IntentService: an android Service subclass you may extend which contains a single background thread on which work without an associated Activity can be done
  • AlarmManager: a mechanism provided by the Android system to start Android components at a particular time, but which forgets everything upon reboot
  • JobScheduler: 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 coordinated

How 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:

  • Are you performing a task which relates directly to an Activity the user is interacting with visually on screen right now?

Consider HandlerThread, AsyncTask, or ExecutorService

  • Are you playing music in the background or something else the user wants to control via notification?

Consider Service paired with a HandlerThread or something similar.

  • Are you performing a task which needs to occur sooner or later, but is not directly related to what is happening on screen right now?

Consider WorkManager, or AlarmManager with IntentService

  • If the user powers off their device right when your task is about to start do you want to try again when the device is powered back on?

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/

like image 149
satur9nine Avatar answered Dec 06 '22 10:12

satur9nine