Every Android app has a main thread which is in charge of handling UI (including measuring and drawing views), coordinating user interactions, and receiving lifecycle events. If there is too much work happening on this thread, the app appears to hang or slow down, leading to an undesirable user experience. Any long-running computations and operations such as decoding a bitmap, accessing the disk, or performing network requests should be done on a separate background thread. In general, anything that takes more than a few milliseconds should be delegated to a background thread. Some of these tasks may be required to be performed while the user is actively interacting with the app. To learn how you can run tasks on background threads and off the main UI thread while the app is actively being used, please take a look at the threading solutions guide.
Applications may also require some tasks to run even when the user is not actively using the app such as syncing periodically with a backend server or fetching new content within an app on a periodic basis. Applications may also require services to run immediately to completion even after the user has completed interacting with the app. This guide will help you learn which solution best meets your needs for these use cases.
Challenges in background processing
Background tasks consume a device's limited resources, like RAM and battery. This may result in a poor experience for the user if not handled correctly.
In order to maximize battery and enforce good app behavior, Android restricts background work when the app (or a foreground service notification) is not visible to the user.
- Android 6.0 (API level 23) introduced Doze mode and app standby. Doze mode restricts app behavior when the screen is off and the device is stationary. App standby puts unused applications into a special state that restricts their network access, jobs, and syncs.
- Android 7.0 (API level 24) limited implicit broadcasts and introduced Doze-on-the-Go.
- Android 8.0 (API level 26) further limited background behavior, such as getting location in the background and releasing cached wakelocks.
- Android 9 (API level 28) introduced App Standby Buckets, in which app requests for resources are dynamically prioritized based on app usage patterns.
It is important to understand your task needs and choose the right solution adhering to system best practices in scheduling your background job.
Choosing the right solution for your work
Can the work be deferred, or does it need to happen right away? For example, if you need to fetch some data from the network in response to the user clicking a button, that work must be done right away. However, if you want to upload your logs to the server, that work can be deferred without affecting your app’s performance or user expectations.
Is the work dependent on system conditions? You might want your job to run only when the device meets certain conditions, such as being connected to power, having internet connectivity, and so on. For example, your app might periodically need to compress its stored data. To avoid affecting the user, you would want this job to happen only when the device is charging and idle.
Does the job need to run at a precise time? A calendar app might let a user set up a reminder for an event at a specific time. The user expects to see the reminder notification at the correct time. In other cases, the app may not care precisely when the job runs. The app might have general requirements—like, "Job A must run first, then Job B, then Job C"—but it doesn't require jobs to run at a specific time.
For work that is deferrable and expected to run even if your device or application restarts, use WorkManager. WorkManager is an Android library that gracefully runs deferrable background work when the work's conditions (like network availability and power) are satisfied.
WorkManager offers a backwards compatible (API level 14+) API leveraging
JobScheduler API (API
level 23+) and above to help optimize battery life and batch jobs and a combination of
BroadcastReceiver on lower devices.
For user-initiated work that need to run immediately and must execute to completion, use a foreground service. Using a foreground service tells the system that the app is doing something important and it shouldn’t be killed. Foreground services are visible to users via a non-dismissible notification in the notification tray.
If you need to run a job at a precise time, use
launches your app, if necessary, to do the job at the time you specify. However,
if your job does not need to run at a precise time,
WorkManager is a better
WorkManager is better able to balance system resources. For example,
if you need to run a job every hour or so, but don't need the job to run
at a specific time, you should use
WorkManager to set up a recurring job.
If your app is performing long-running HTTP downloads, consider using DownloadManager. Clients may request that a URI be downloaded to a particular destination file that may be outside of the app process. The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots.