When an application component starts and the application does not have any other components running, the Android system starts a new Linux process for the application with a single thread of execution. By default, all components of the same application run in the same process and thread (called the "main" thread). If an application component starts and there already exists a process for that application (because another component from the application exists), then the component is started within that process and uses the same thread of execution. However, you can arrange for different components in your application to run in separate processes, and you can create additional threads for any process.
This document discusses how processes and threads work in an Android application.
Processes
By default, all components of the same application run in the same process and most applications should not change this. However, if you find that you need to control which process a certain component belongs to, you can do so in the manifest file.
The manifest entry for each type of component element—<activity>
, <service>
, <receiver>
, and <provider>
—supports an android:process
attribute that can specify a
process in which that component should run. You can set this attribute so that each component runs
in its own process or so that some components share a process while others do not. You can also set
android:process
so that components of different applications run in the same
process—provided that the applications share the same Linux user ID and are signed with the
same certificates.
The <application>
element also supports an android:process
attribute, to set a
default value that applies to all components.
Android might decide to shut down a process at some point, when resources are required by other processes that are more immediately serving the user. Application components running in the process that's killed are consequently destroyed. A process is started again for those components when there's again work for them to do.
When deciding which processes to kill, the Android system weighs their relative importance to the user. For example, it more readily shuts down a process hosting activities that are no longer visible on screen, compared to a process hosting visible activities. The decision whether to terminate a process, therefore, depends on the state of the components running in that process.
The details of the process lifecycle and its relationship to application states are discussed in Processes and Application Lifecycle.
Threads
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 to
the appropriate user interface widgets, including drawing events. It is also
almost always the thread in which your application interacts with components
from the Android UI toolkit (components from the android.widget
and
android.view
packages). As such, the main thread is also sometimes
called the UI thread. However, under special circumstances, an app's main
thread might not be its UI thread; for more information, see Thread
annotations.
The system does not create a separate thread for each instance of a component. All
components that run in the same process are instantiated in the UI thread, and system calls to
each component are dispatched from that thread. Consequently, methods that respond to system
callbacks (such as onKeyDown()
to report user actions
or a lifecycle callback method) always run in the UI thread of the process.
For instance, when the user touches a button on the screen, your app's UI thread dispatches the touch event to the widget, which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget that it should redraw itself.
When your app performs intensive work in response to user interaction, this single thread model can yield poor performance unless you implement your application properly. Specifically, if everything is happening in the UI thread, performing long operations such as network access or database queries will block the whole UI. When the thread is blocked, no events can be dispatched, including drawing events. From the user's perspective, the application appears to hang. Even worse, if the UI thread is blocked for more than a few seconds (about 5 seconds currently) the user is presented with the infamous "application not responding" (ANR) dialog. The user might then decide to quit your application and uninstall it if they are unhappy.
Additionally, the Android UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:
- Do not block the UI thread
- Do not access the Android UI toolkit from outside the UI thread
Worker threads
Because of the single threaded model described above, it's vital to the responsiveness of your application's UI that you do not block the UI thread. If you have operations to perform that are not instantaneous, you should make sure to do them in separate threads ("background" or "worker" threads).
However, note that you cannot update the UI from any thread other than the UI thread or the "main" thread.
To fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Kotlin
fun onClick(v: View) { Thread(Runnable { // a potentially time consuming task val bitmap = processBitMap("image.png") imageView.post { imageView.setImageBitmap(bitmap) } }).start() }
Java
public void onClick(View v) { new Thread(new Runnable() { public void run() { // a potentially time consuming task final Bitmap bitmap = processBitMap("image.png"); imageView.post(new Runnable() { public void run() { imageView.setImageBitmap(bitmap); } }); } }).start(); }
This implementation is thread-safe: the background operation is done from a separate thread
while the ImageView
is always manipulated from the UI thread.
However, as the complexity of the operation grows, this kind of code can get complicated and
difficult to maintain. To handle more complex interactions with a worker thread, you might consider
using a Handler
in your worker thread,
to process messages delivered from the UI thread. See
Threading on Android for a full explanation of how to
schedule work on background threads and communicate back to the UI thread.
Thread-safe methods
In some situations, the methods you implement might be called from more than one thread, and therefore must be written to be thread-safe.
This is primarily true for methods that can be called remotely—such as methods in a bound service. When a call on a
method implemented in an IBinder
originates in the same process in which the
IBinder
is running, the method is executed in the caller's thread.
However, when the call originates in another process, the method is executed in a thread chosen from
a pool of threads that the system maintains in the same process as the IBinder
(it's not executed in the UI thread of the process). For example, whereas a service's
onBind()
method would be called from the UI thread of the
service's process, methods implemented in the object that onBind()
returns (for example, a subclass that implements RPC methods) would be called from threads
in the pool. Because a service can have more than one client, more than one pool thread can engage
the same IBinder
method at the same time. IBinder
methods must, therefore, be implemented to be thread-safe.
Similarly, a content provider can receive data requests that originate in other processes.
Although the ContentResolver
and ContentProvider
classes hide the details of how the interprocess communication is managed, ContentProvider
methods that respond to those requests—the methods query()
, insert()
, delete()
, update()
, and getType()
—are called from a pool of threads in the content provider's process, not the UI
thread for the process. Because these methods might be called from any number of threads at the
same time, they too must be implemented to be thread-safe.
Interprocess communication
Android offers a mechanism for interprocess communication (IPC) using remote procedure calls (RPCs), in which a method is called by an activity or other application component, but executed remotely (in another process), with any result returned back to the caller. This entails decomposing a method call and its data to a level the operating system can understand, transmitting it from the local process and address space to the remote process and address space, then reassembling and reenacting the call there. Return values are then transmitted in the opposite direction. Android provides all the code to perform these IPC transactions, so you can focus on defining and implementing the RPC programming interface.
To perform IPC, your application must bind to a service, using bindService()
. For more information, see the Services developer guide.