Skip to content

Managing Threads and Custom Services

Nathan Esquenazi edited this page Aug 8, 2015 · 40 revisions

Overview

This guide focuses on defining custom services including the various mechanisms for sending messages and managing threads to do background work. Android has many different abstractions related to messages and thread management which need to be summarized and understood. These threading abstractions are often related to defining custom services because a service by default still runs in the application's main thread and background work must be delegated to threads.

TODO: Needs Attention

Services and Threading

Services and thread management are closely related but also distinct topics. A service is simply a component that can run in the background even when the user is not interacting with your app. You should only create a service if you need to perform work while your app isn't open.

Thread management is important to understand because a custom service still runs in your application's main thread by default. If you create a custom Service, then you will still need to manage the background threads manually unless the IntentService is leveraged.

Thread Management

As a result of the major problems with blocking the UI Thread outlined below, every Android app should utilize background threads to perform long-running tasks such as I/O operations including reading from or writing to the disk and performing network operations. However, there are several different abstractions for managing threads in the Android framework. The following table breaks down the most practical options:

Type Description Built On
[[AsyncTask Creating-and-Executing-Async-Tasks]] Short sequential tasks to update UI within activity context
HandlerThread Sequentially runs tasks on a single thread Handler, Looper
ThreadPoolExecutor Concurrently runs tasks using a thread pool Executor, ExecutorService

Understanding the Main Thread

When an application is launched, the system creates a thread of execution for the application, called "main." This thread is very important because it is in charge of dispatching events and rendering the user interface and is usually called the UI thread. All components (activities, services, etc) and their executed code run in the same process and are instantiated by default in the UI thread.

Keep in mind that performing long operations such as network access or database queries in the UI thread will block the entire app UI from responding. When the UI thread is blocked, no events can be dispatched, including drawing events. From the user's perspective, the application will appear to freeze. Additionally, keep in mind the Android UI toolkit is not thread-safe and as such you must not manipulate your UI from a background thread.

Using HandlerThread

HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
 
// Create a handler attached to the HandlerThread's Looper
mHandler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // Process messages here
    }
};
 
// Now send messages using mHandler.sendMessage()

Threading Glossary

All threading management options within Android including AsyncTask, HandlerThread and ThreadPoolExecutor are all built on even more foundational classes that power threads. The following is a glossary of concepts that power threading within the Android OS:

Name Description
Runnable Represents code that can be executed on any thread usually scheduled through a handler
Thread Concurrent unit of execution which runs code specified in a Runnable
Message Represents data that can be sent or received through a Handler
Handler Processes Runnable or Message objects on a thread.
Looper Loop that queues and sends Runnable or Message objects to a Handler
MessageQueue Stores the list of Runnable or Message objects dispatched by the Looper

For a more detailed description of these terms, check out this excellent post on the subject.

Custom Services

Background Services with IntentService

In 90% of cases when you need a background service doing a task when your app is closed, you will leverage the IntentService as your first tool for the job. However, IntentService does have a few limitations. The biggest limitation is that the IntentService uses a single worker thread to handle start requests one at a time. However, as long as you don't require that your service handle multiple requests simultaneously, the IntentService is typically the easiest tool for the job.

However, in certain specialized cases where you do need background tasks to be processed in parallel using a concurrent thread pool and as such you cannot use IntentService and must extend from Service directly. The rest of this guide is focused on that particular use case.

References

Finding these guides helpful?

We need help from the broader community to improve these guides, add new topics and keep the topics up-to-date. See our contribution guidelines here and our topic issues list for great ways to help out.

Check these same guides through our standalone viewer for a better browsing experience and an improved search. Follow us on twitter @codepath for access to more useful Android development resources.

Clone this wiki locally