Android
Background Thread
Code Execution
Multithreading
Android Development

How can I run code on a background thread on Android?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Running code on a background thread is a common requirement in Android development, particularly when dealing with tasks that can block the UI thread such as network requests, file operations, or complex computations. Leveraging background threads helps maintain a responsive and smooth user interface.

In this article, we'll explore several ways to run code on a background thread in Android, providing examples and explanations for each approach.

Understanding Threads in Android

Before diving into implementation details, it's crucial to understand how threading works in Android:

  • UI Thread: Also known as the main thread, it is responsible for handling all the UI operations, including user interactions and lifecycle events. Blocking this thread by executing long-running tasks can make the app unresponsive, leading to an undesirable user experience.
  • Background Threads: Separate threads that can execute long-running operations without affecting the UI thread.

Methods for Running Code in Background Threads

There are multiple methods available in Android for executing code on background threads:

  1. Java Threads
  2. Handler and HandlerThread
  3. AsyncTask (Deprecated)
  4. Executors
  5. Loaders
  6. WorkManager
  7. Kotlin Coroutines

1. Java Threads

The simplest way to create a background thread is by using the Thread class:

java
1Thread backgroundThread = new Thread(new Runnable() {
2    @Override
3    public void run() {
4        // Code to execute in background
5    }
6});
7backgroundThread.start();

While simple, managing threads manually can be complex, especially when handling thread synchronization and lifecycle events.

2. Handler and HandlerThread

Handler can be used with HandlerThread to simplify message passing between threads:

java
1HandlerThread handlerThread = new HandlerThread("BackgroundThread");
2handlerThread.start();
3Handler handler = new Handler(handlerThread.getLooper());
4
5handler.post(new Runnable() {
6    @Override
7    public void run() {
8        // Code to execute in background
9    }
10});

3. AsyncTask (Deprecated)

Though deprecated in Android API level 30, AsyncTask was a popular way to perform background work and update the UI thread:

java
1private class ExampleAsyncTask extends AsyncTask<Void, Void, String> {
2    @Override
3    protected String doInBackground(Void... voids) {
4        // Background operation
5        return "Result";
6    }
7
8    @Override
9    protected void onPostExecute(String result) {
10        // Update UI with result
11    }
12}

It's recommended to use other alternatives for new projects due to its limitations and inefficiencies.

4. Executors

The Executor framework provides a flexible and powerful way to manage background threads:

java
1ExecutorService executorService = Executors.newSingleThreadExecutor();
2
3executorService.execute(new Runnable() {
4    @Override
5    public void run() {
6        // Background task
7    }
8});

Executors simplify thread management by allowing thread reuse and limiting the number of concurrent threads.

5. Loaders

Loaders were designed to manage background task execution and data retention across configuration changes:

java
1LoaderManager.getInstance(this).initLoader(0, null, new LoaderManager.LoaderCallbacks<String>() {
2    @Override
3    public Loader<String> onCreateLoader(int id, Bundle args) {
4        return new AsyncTaskLoader<String>(getApplicationContext()) {
5            @Override
6            public String loadInBackground() {
7                // Perform background task
8                return "Result";
9            }
10        };
11    }
12
13    @Override
14    public void onLoadFinished(Loader<String> loader, String data) {
15        // Use result in UI
16    }
17
18    @Override
19    public void onLoaderReset(Loader<String> loader) {
20        // Reset loader
21    }
22});

With the introduction of Architecture Components, Loaders are now considered obsolete.

6. WorkManager

WorkManager is a robust solution for running deferrable and guaranteed work in background:

java
1public class ExampleWorker extends Worker {
2    public ExampleWorker(@NonNull Context context, @NonNull WorkerParameters params) {
3        super(context, params);
4    }
5
6    @NonNull
7    @Override
8    public Result doWork() {
9        // Background task
10        return Result.success();
11    }
12}
13
14// Enqueue the work
15WorkManager workManager = WorkManager.getInstance(context);
16workManager.enqueue(new OneTimeWorkRequest.Builder(ExampleWorker.class).build());

I'd recommend WorkManager for tasks that require guaranteed execution, even across app restarts.

7. Kotlin Coroutines

Kotlin Coroutines offer a modern solution for managing background tasks with minimal boilerplate:

kotlin
GlobalScope.launch(Dispatchers.IO) {
    // Background task
}

Coroutines allow for asynchronous code execution in a sequential manner, simplifying complex operations like network requests.

Summary Table

MethodDescriptionUse Case
Java ThreadsLow-level API for creating threadsSimple background execution, inefficient for complex apps
HandlerThreadManages message queues for background threadsMessage passing between threads
AsyncTaskSimplifies background tasks and UI updateDeprecated, avoid use in new projects
ExecutorsHigh-level framework for thread managementEfficient thread reuse and resource management
LoadersManages background data across configuration changesConsidered obsolete, avoid in new projects
WorkManagerManages deferrable background tasksGuaranteed execution, suitable for periodic work
Kotlin CoroutinesSimplifies asynchronous programmingModern approach, minimal boilerplate

Conclusion

Running code on a background thread in Android is crucial for maintaining a responsive app. Each method has its specific strengths and limitations, and the choice depends on the particular requirements and constraints of your app. While older methods like AsyncTask and Loaders have been deprecated or are considered obsolete, modern solutions like WorkManager and Kotlin Coroutines offer a robust and scalable approach to managing background execution. By carefully selecting the suitable method, you can ensure that your app remains responsive and efficient.


Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.