This article is translated from Android official documentation When an Android application component is started, if no other components of the application are running at the same time, the system will start a new Linux process for the application as a single thread. By default, all components of the same application run in the same process and thread (usually called the "main" thread of the application). If an application component is started and the process of the application already exists (because other components of the application have been started before), the component will be started in this process and executed in the main thread of the application. However, you can also have components in your application run in different processes, and you can add additional threads to any process. This article discusses how processes and threads work in Android programs. process By default, all components of the same application run in the same process, which is the case for most applications. However, if you find that you need a component in your application to run in a specific process, you can set it in the manifest file. The manifest file provides an android:process attribute for each component element—<activity>, <service>, <receiver>, and <provider>. By setting this attribute, you can specify a specific process for a component to run in. You can set each component to run in its own process, or you can set some components to share a process while others do not. You can also set components of different applications to run in the same process—this allows those applications to share the same Linux user ID and be authenticated by the same certificates. The <application> element also supports the android:process attribute. Setting this attribute will make all components in the application inherit this attribute by default. Android may shut down a process when there is less remaining system memory and other processes that directly serve users need to apply for memory. At this time, the components in this process will also be killed one by one. When new tasks arrive for these components, their corresponding processes will be started again. When deciding which processes to kill, the Android system weighs the importance of those processes to the user. For example, the system is more likely to kill processes that host activities that are no longer visible than processes that host visible activities. The decision to terminate a process depends on the state of the components running in the process. Below we discuss some of the rules used when killing processes. Process Lifecycle As a multi-tasking system, Android can certainly keep an application process as long as possible. However, as new or more important processes require more memory, the system has to gradually terminate old processes to gain memory. In order to declare which processes to keep and which to kill, the system generates an "importance hierarchy" for each process based on the components in these processes and the status of these components. The processes in the highest importance hierarchy will be cleared first, followed by the more important ones, and so on, according to the system's needs. There are 5 levels in this importance hierarchy. The following list shows the different types of processes in order of importance (the first process is the most important and will be killed first):
Android rates the components in a process based on their importance as much as possible. For example, if a process contains a service and a visible activity, then the process will be rated as a visible process, not a service process. Additionally, a process's rating may be boosted by other processes that depend on it—a process that serves other processes will never have a lower rating than the process it is serving. For example, if a content provider in process A is serving a client in process B, or if a service in process A is bound to a component in process B, process A will be considered by the system to have at least a higher rating than process B. Because a process with a service running in it is rated higher than a process with background activities, when an activity starts a long-running operation, it is best to start a service to do the operation rather than simply creating a worker thread—especially when the long-running operation might bring down the activity. For example, an activity that uploads a picture to a website should start a worker thread to perform the upload. That way, the upload can continue in the background even if the user navigates away from the activity. Using a service ensures that the operation is at least at the "service process" priority, regardless of what happens to the activity. This is why broadcast receivers should use services rather than simply putting long-running operations in threads. Threads When an application starts, the system creates a thread for it, called the "main thread". This thread is important because it handles dispatching events to relevant user interface widgets, including drawing events. Your application also interacts with components from the Android UI toolkit (including components from the android.widget and android.view packages) in this thread. Therefore, this main thread is sometimes called the UI thread. The system does not create a separate thread for each component. All components in the same process are instantiated in the UI thread, and the system calls each component through this thread. Therefore, methods that respond to system calls (such as the onKeyDown() method used to capture user actions or a lifecycle callback function) are all run in the UI thread of the process. For example, when the user clicks a button on the screen, your application's UI thread passes the click event to the widget, which then sets its pressed state and sends an invalidation request to the event queue. The UI thread dequeues the request and then processes it (notifying the widget to redraw itself). When your application's interaction with the user requires a high response speed, this single-threaded model may produce bad results (unless you implement your application well). In particular, when everything in the application happens in the UI thread, long operations such as accessing network data and database queries will block the entire UI thread. When the entire thread is blocked, no events can be delivered, including drawing events. This makes the application appear to the user to be suspended. Even worse, if the UI thread is blocked for more than a few seconds (currently 5 seconds), the system will pop up the infamous "application not responding" (ANR) dialog box. At this time, the user may choose to exit your application or even uninstall it. In addition, Android's UI thread is not thread-safe. So you can't operate your UI in a worker thread—you must operate your UI on the UI thread. There are two simple rules about Android's single-threaded model:
Worker Threads Because of the single-threaded model described above, it is important to ensure that your app's UI is responsive and that the UI thread is not blocked. If you cannot allow operations in your app to be executed in a short period of time, then you should make sure to put these operations in a separate thread ("background" or "worker" thread). For example, the following code downloads an image in an additional thread and displays it in an ImageView:
At first this code looks good because it creates a new thread to handle the network operation. However, it violates the second rule of the single thread model: do not access the Android UI toolkit from a non-UI thread—this example modifies the ImageView in a worker thread. This can lead to unexpected results and is difficult to debug. To fix this problem, Android provides several methods to access the Android UI toolkit from non-UI threads. See the following list for details:
Then, you can use the View.post(Runnable) method to modify the previous code:
Now this solution is thread-safe: after the network operation is completed in a separate thread, the UI thread will operate on the ImageView. However, as the complexity of the operation grows, the code will become more and more complex and difficult to maintain. In order to handle more complex interactions with worker threads, you can consider using Handler in the worker thread to handle messages in the UI thread. Perhaps the best solution is to inherit the AsyncTask class, which simplifies the execution of worker thread tasks that need to interact with the UI. Using AsyncTask AsyncTask allows you to perform asynchronous operations on the UI. It performs some blocking operations in a worker thread and then passes the results to the UI main thread, without requiring you to handle threads or handlers during this process. To use it, you must inherit AsyncTask and implement the doInBackground() callback method, which runs in a background thread pool. If you need to update the UI, you should implement onPostExecute(), which takes the result from doInBackground() and runs it in the UI thread, so you can update your UI safely. You can run this task by calling the execute() method on the UI thread. For example, you could implement the previous example using an AsyncTask:
Now the UI is safe and the code is simpler because AsyncTask separates what needs to be done in the worker thread from what needs to be done in the UI thread. You should read the reference documentation of
Note: Another problem you may encounter when using worker threads is that your activity may be restarted unexpectedly due to runtime configuration changes (such as the user changing the screen orientation), which may kill your worker thread. To solve this problem you can refer to the Shelves project. Thread-safe methods In some cases, the method you implement may be called by multiple threads, so you must write it to be thread-safe.
Article address: Android processes and threads |
<<: DAMO holds a seminar on self-controllable database software products and big data applications
>>: A design study guide for programmers
Where should I buy dog meat online? Where can I...
Nature Cover The pictures and characters in this ...
What is operational thinking ? Operational thinki...
Data from the third quarter of 2020 show that the...
Coffee is a daily drink in modern people's li...
Through the analysis and summary of this article,...
A River Full of Red: Writing Thoughts (Song Dynas...
“The two core elements of customer acquisition ar...
Delaying retirement has been one of the hot topic...
The environment we live in now is an era full of ...
"He knew that he had the most intelligent mi...
Recently, Mobileye, a world-renowned provider of ...
This series of articles may reach nearly 50,000 w...
The current situation of online education compani...