Android programmers must master the knowledge points-multi-process and multi-threading

Source: Internet
Author: User
Tags terminates

When an app component starts and the app does not run any other components, the Android system launches a new Linux process for the app using a single thread of execution. By default, all components of the same app run in the same process and thread (called the "main" thread). If an app component starts and the app already has a process (because there are other components of the app), the component starts in the process and uses the same execution thread. However, you can schedule other components in your app to run in a separate process and create additional threads for any process.

This article describes how processes and threads work in Android apps.

Process
By default, all components of the same app run in the same process, and most apps don't change that. However, if you find that you need to control the process that a component belongs to, you can do so in the manifest file.

Manifest file entries for various component elements-activity, service, receiver, and provider-all support the Android:process property, which specifies which process the component should run in. You can set this property so that each component runs in its own process, or that some components share a process, while others are not shared. In addition, you can set up android:process to allow components from different apps to run in the same process, but only if they share the same Linux user ID and sign with the same certificate.

In addition, the application element supports the Android:process property to set default values that apply to all components.

If there is not enough memory, and other processes that provide a more urgent service to the user require memory, Android may decide to close a process at some point. Application components that run in the terminated process are also destroyed. When these components need to be run again, the system restarts the process for them.

When deciding which process to terminate, the Android system will weigh their relative importance to the user. For example, it is more likely to turn off the process of activity that is no longer visible on the managed screen, as opposed to the process that hosts the visible activity. Therefore, the decision whether to terminate a process depends on the state of the component that is running in the process. Below, we describe the rules used to determine the termination process.

Process life cycle
The Android system will keep the application process as long as possible, but in order to create a new process or run a more important process, the old process eventually needs to be removed to reclaim memory. To determine which processes are retained or terminated, each process is placed into the importance hierarchy, based on the components that are running in the process and the state of those components. When necessary, the system first removes the least-important process, then a process that is less important, and so on, to reclaim system resources.

The importance hierarchy has a total of 5 levels.
The following list lists the various processes by importance (the first process is the most important and will be the last one to be terminated):

Foreground process
The process required for the user's current operation. If a process meets any of the following conditions, it is considered a foreground process: the activity that the managed user is interacting with (the Onresume () method that has called activity) hosts a Service that is bound to the activity that the user is interacting with hosting the S that are running in the foreground The Ervice (service has called Startforeground ()) hosts a service that is performing a lifecycle callback (OnCreate (), OnStart (), or OnDestroy ()) that hosts the one that is executing its onreceive () method. Broadcastreceiver Typically, there are few foreground processes at any given time. The system terminates them only if the memory is not sufficient to support them while continuing to run this as a last resort. At this point, the device tends to have reached the memory paging state, so some foreground processes need to be terminated to ensure that the user interface responds properly.

Visible process
A process that does not have any foreground components, but still affects what the user sees on the screen. If a process meets any of the following conditions, it is considered a visible process: Hosts an Activity that is not in the foreground but is still visible to the user (its OnPause () method has been called). This can happen, for example, if the foreground activity launches a dialog box that allows the previous activity to be displayed later. A Service that is managed to bind to a visible (or foreground) Activity. The visible process is considered to be an extremely important process, and the system does not terminate the process unless it must be terminated in order to maintain all foreground processes running concurrently.

Service process
Running a service that has been started with the StartService () method and is not part of the above two higher category processes. Although the service process is not directly related to what the user sees, they typically perform actions that are of interest to the user (for example, playing music in the background or downloading data from the network). Therefore, the system keeps the service process running unless the memory is insufficient to maintain all foreground and visible processes running concurrently.

Background process
Contains the current process of activity that is not visible to the user (the OnStop () method of the activity is called). These processes have no direct impact on the user experience, and the system may terminate them at any time to reclaim memory for use by foreground processes, visible processes, or service processes. There are often many background processes running, so they are saved in the LRU (least recently used) list to ensure that the last one that contains the Activity that the user recently viewed is terminated. If an activity correctly implements the life cycle method and saves its current state, terminating its process does not have a noticeable impact on the user experience, because when the user navigates back to the activity, the activity restores all of its visible state. For information about saving and restoring status, see the activity documentation.

Empty process
Processes that do not contain any active app components. The only purpose of preserving this process is to use it as a cache to shorten the startup time required for the next component to run. To keep the overall system resources balanced between the process cache and the underlying kernel cache, the system often terminates these processes. Depending on the importance of the currently active component in the process, Android will evaluate the process to the highest level it can reach. For example, if a process hosts services and visible Activity, the process is evaluated as visible, not a service process.

In addition, the level of a process may be enhanced by the dependency of other processes on it, that is, the process that serves the other process is never less than the process it serves. For example, if the content provider in process a serves the client in process B, or if the service in process A is bound to a component in process B, process A is always considered as important at least as it is for process B.

Because the process that runs the service has a higher level than the process that hosts the background activity, the activity that initiates the long-running operation is best to start the service for the operation, rather than simply creating the worker thread, especially if the operation is more durable than the activity. For example, an activity that is uploading a picture to a website should start the service to perform the upload, so that the upload can continue in the background even if the user exits the activity. Using the service guarantees that, regardless of what happens to the activity, the operation has at least the service process priority. Similarly, a broadcast receiver should use the service instead of simply putting lengthy operations into the thread.

Thread
When the app starts, an execution thread called the main thread is created for the app. This thread is important because it is responsible for assigning events to the appropriate user interface widgets, which include drawing events. It is also a thread that applies to interact with the Android UI Toolkit components (components from the Android.widget and Android.view packages). Therefore, the main thread is sometimes referred to as the UI thread.

The system does not create a separate thread for each component instance. All components running in the same process are instantiated in the UI thread, and the system calls to each component are assigned by that thread. Therefore, the method that responds to system callbacks (for example, the OnKeyDown () or lifecycle callback method that reports user actions) always runs in the UI thread of the process.

For example, when a user touches a button on the screen, the app's UI thread assigns the touch event to the widget, and the widget in turn sets its pressed state and publishes the invalidation request to the event queue. The UI thread cancels the request from the queue and notifies the widget that it should redraw itself.

This single-threaded pattern can lead to poor performance when the application performs heavy tasks in response to user interaction, unless the application is implemented correctly. Specifically, if the UI thread needs to handle all tasks, performing lengthy operations (for example, network access or database queries) will block the entire UI. Once the thread is blocked, no events, including drawing events, can be dispatched. From the user's point of view, the app appears to be suspended. Worse, if the UI thread is blocked for more than a few seconds (currently about 5 seconds), the user will see a boring "app unresponsive" (ANR) dialog box. If the user is dissatisfied, they may decide to quit and uninstall the app.

In addition, the Android UI Toolkit is not a thread-safe tool pack. Therefore, you must not manipulate the UI through a worker thread, but only through the UI thread. Therefore, Android's single-threaded mode must comply with two rules:

Do not block the UI thread
Do not access the Android UI Toolkit outside of the UI thread

Worker threads
Depending on the single threading pattern described above, the key to ensuring the responsiveness of the application UI is that the UI thread cannot be blocked. If the actions performed do not complete quickly, you should ensure that they run in a separate thread (the "background" or "work" thread).

For example, the following code demonstrates a click listener to download an image from a separate thread and display it in ImageView:

public void OnClick (View v) {
New Thread (New Runnable () {
public void Run () {
Bitmap B = loadimagefromnetwork ("Http://example.com/image.png");
Mimageview.setimagebitmap (b);
}
}). Start ();
}
At first glance, this code seems to work well because it creates a new thread to handle the network operation. However, it violates the second rule of single-threaded mode: Do not access the Android UI toolkit outside the UI thread-this example modifies ImageView from the worker thread, not the UI threads. This can lead to ambiguous and unpredictable behavior, but it is difficult and time-consuming to track this line.

To address this issue, Android provides several ways to access the UI thread from other threads.

Several useful methods are listed below:
Activity.runonuithread (Runnable) view.post (Runnable) view.postdelayed (Runnable, long)

For example, you can fix the above code by using the View.post (Runnable) method:

public void OnClick (View v) {
New Thread (New Runnable () {
public void Run () {
Final Bitmap Bitmap =
Loadimagefromnetwork ("Http://example.com/image.png");
Mimageview.post (New Runnable () {
public void Run () {
Mimageview.setimagebitmap (bitmap);
}
});
}
}). Start ();
}
The above implementations are now thread-safe: Complete network operations in a separate thread, and manipulate ImageView in the UI thread.

However, as operations become more complex, such code can become complex and difficult to maintain. To handle more complex interactions through a worker thread, consider using Handler in a worker thread to process messages from the UI thread. Of course, the best solution might be to extend the Asynctask class, which simplifies the work-thread tasks that are required to interact with the UI.

Using Asynctask
Asynctask allows asynchronous operations to be performed on the user interface. It blocks the actions in the worker thread and then publishes the results in the UI thread without having to handle the line Rountines accesses/or handlers yourself.

To use it, you must create a subclass of Asynctask and implement the Doinbackground () callback method, which will run in the background thread pool. To update the UI, you should implement OnPostExecute () to pass the results returned by Doinbackground () and run in the UI thread so that you can safely update the UI. Later, you can run the task by calling execute () from the UI thread.

For example, you can use Asynctask to implement the above example in the following ways:

public void OnClick (View v) {
New Downloadimagetask (). Execute ("Http://example.com/image.png");
}

Private class Downloadimagetask extends Asynctask<string, Void, bitmap> {
/** The system calls this to perform work in a worker thread and

    • Delivers it the parameters given to Asynctask.execute () */
      Protected Bitmap doinbackground (String ... urls) {
      Return Loadimagefromnetwork (Urls[0]);
      }

      /** The system calls the perform work in the UI thread and delivers

    • The result from Doinbackground () */
      protected void OnPostExecute (Bitmap result) {
      Mimageview.setimagebitmap (result);
      }
      }
      Now that the UI is secure, the code is simplified because the task is decomposed into two parts: part should be done within the worker thread, and the other part should be done within the UI thread.

Here's a brief overview of how Asynctask works, but to get a complete picture of how to use this class, you should read the Asynctask reference documentation:

You can use generics to specify parameter types, progress values, and task final value methods Doinbackground () will automatically execute on worker threads OnPreExecute (), OnPostExecute (), and Onprogressupdate () are called in the UI thread The value returned by Doinbackground () is sent to OnPostExecute () and you can call Publishprogress () in Doinbackground () at any time to execute onprogressupdate () in the UI thread You can cancel tasks in any thread at any time note: You may encounter another problem when working with worker threads: Runtime configuration changes (for example, the user changes the screen orientation) cause an Activity to restart unexpectedly, which may destroy the worker thread. To learn how to persist in performing tasks in such a reboot, and to correctly cancel tasks when the activity is destroyed, see the source code for the Bookshelf sample app.

Thread-Safe methods
In some cases, the methods you implement may be called from multiple threads, so you must make sure that they meet the thread-safety requirements when writing these methods.

This applies primarily to methods that can be called remotely, such as methods in a binding service. If the call to the implemented method in IBinder originates from the same process that is running IBinder, the method executes in the caller's thread. However, if the call originates from another process, the method executes in a thread selected from the thread pool (rather than executing in the process's UI thread), and the thread pool is maintained by the system in the same process as IBinder. For example, even if the Onbind () method of the service is called from the UI thread of the service process, the method implemented in the object returned by Onbind () (for example, a subclass that implements the RPC method) will still be called from a thread in the thread pool. Because a service can have multiple clients, there may be multiple pool threads that use the same IBinder method at the same time. Therefore, the IBinder method must be implemented as a thread-safe method.

Similarly, a content provider can receive data requests from other processes. Although the Contentresolver and ContentProvider classes hide details on how to manage interprocess communication, the ContentProvider method of responding to these requests (query (), insert (), delete (), update () and the GetType () method) will be called from the thread pool of the process where the content provider resides, rather than from the UI thread of the process. Because these methods may be called from any number of threads at the same time, they must also be implemented as thread-safe methods.

Inter-process communication
Android uses remote procedure call (RPC) to provide an interprocess communication (IPC) mechanism through which methods called by Activity or other application components are executed remotely (in other processes), and all results are returned to the caller. This requires that the method invocation and its data be decomposed to a level that the operating system can recognize, transferred from the local process and address space to the remote process and address space, and then reassembled and executed in the remote process. The return value is then transferred back in the opposite direction. Android provides all the code needed to execute these IPC transactions, so you only need to focus on defining and implementing RPC programming interfaces.

To perform the IPC, you must bind the app to the service using Bindservice ()

Knowledge points that Android programmers must master-multi-process and multithreaded

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.