您的位置:首页 > 其它

Processes and Threads(英文文档)

2012-03-03 15:50 387 查看
When an application component starts and the application does not have any other componentsrunning, the Android system starts a new Linux process for the application with a single thread ofexecution. 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 processfor that application (because another component from the application exists), then the component isstarted within that process and
uses the same thread of execution. However, you can arrange fordifferent components in your application to run in separate processes, and you can create additionalthreads 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 applicationsshould not change this. However, if you find that you need to control which process a certaincomponent 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 aprocess in which that component should run. You can set this attribute so that each component runsin 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 sameprocess—provided that the applications share the same Linux user ID and are signed with thesame certificates.

The
<application>
element also supports an
android:process
attribute, to set adefault value that applies to all components.

Android might decide to shut down a process at some point, when memory is low and required byother processes that are more immediately serving the user. Applicationcomponents running in the process that's killed are consequently destroyed. A process is startedagain
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 tothe user. For example, it more readily shuts down a process hosting activities that are no longervisible on screen, compared to a process hosting visible activities.
The decision whether toterminate a process, therefore, depends on the state of the components running in that process. Therules used to decide which processes to terminate is discussed below.

Process lifecycle

The Android system tries to maintain an application process for as long as possible, buteventually needs to remove old processes to reclaim memory for new or more important processes. Todetermine which processes to keepand which to kill, the system places
each process into an "importance hierarchy" based on thecomponents running in the process and the state of those components. Processes with the lowestimportance are eliminated first, then those with the next lowest importance, and so on, as necessaryto recover
system resources.

There are five levels in the importance hierarchy. The following list presents the differenttypes of processes in order of importance (the first process ismost important and iskilled last):

Foreground process
A process that is required for what the user is currently doing. A process is considered to be in the foreground if any of the following conditions are true:

It hosts an
Activity
that the user is interacting with (the
Activity
's
onResume()
method has beencalled).
It hosts a
Service
that's bound to the activity that the user isinteracting with.
It hosts a
Service
that's running "in the foreground"—theservice has called
startForeground()
.
It hosts a
Service
that's executing one of its lifecyclecallbacks (
onCreate()
,
onStart()
, or
onDestroy()
).
It hosts a
BroadcastReceiver
that's executing its
onReceive()
method.

Generally, only a few foreground processes exist at any given time. They are killed only asa last resort—if memory is so low that they cannot all continue to run. Generally, at thatpoint, the device has reached a memory paging state, so killing some foreground
processes isrequired to keep the user interface responsive.

Visible process
A process that doesn't have any foreground components, but still can affect what the user sees on screen. A process is considered to be visible if either of the following conditions are true:

It hosts an
Activity
that is not in the foreground, but is stillvisible to the user (its
onPause()
method has been called). This might occur, for example, if the foreground activity started a dialog, which allows theprevious
activity to be seen behind it.
It hosts a
Service
that's bound to a visible (or foreground)activity.

A visible process is considered extremely important and will not be killed unless doing sois required to keep all foreground processes running.

Service process
A process that is running a service that has been started with the
startService()
method and does not fall into either of the twohigher categories. Although service processes are not directly tied to anything the user sees, theyare generally
doing things that the user cares about (such as playing music in the background ordownloading data on the network), so the system keeps them running unless there's not enough memoryto retain them along with all foreground and visible processes.

Background process
A process holding an activity that's not currently visible to the user (the activity's
onStop()
method has been called). These processes have no directimpact on the user experience, and the system can kill them at any time to reclaim memory
for aforeground,visible, or service process. Usually there are many background processes running, so they are keptin an LRU (least recently used) list to ensure that the process with the activity that was mostrecently seen by the user is the last to be killed.
If an activity implements its lifecycle methodscorrectly, and saves its current state, killing its process will not have a visible effect onthe user experience, because when the user navigates back to the activity, the activity restoresall of its visible state.
See the Activitiesdocument for information about saving and restoring state.

Empty process
A process that doesn't hold any active application components. The only reason to keep thiskind of process alive is for caching purposes, to improve startup time the next time a componentneeds to run in it. The system often kills these processes in order
to balance overall systemresources between process caches and the underlying kernel caches.

Android ranks a process at the highest level it can, based upon the importance of thecomponents currently active in the process. For example, if a process hosts a service and a visibleactivity, the process is ranked as a visible process, not a service process.

In addition, a process's ranking might be increased because other processes are dependent onit—a process that is serving another process can never be ranked lower than the process it isserving. For example, if a content provider in process A is serving a
client in process B, or if aservice in process A is bound to a component in process B, process A is always considered at leastas important as process B.

Because a process running a service is ranked higher than a process with background activities,an activity that initiates a long-running operation might do well to start aservice for that operation, rather thansimply create a worker thread—particularly
if the operation will likely outlast the activity.For example, an activity that's uploading a picture to a web site should start a service to performthe upload so that the upload can continue in the background even if the user leaves the activity.Using a service
guarantees that the operation will have at least "service process" priority,regardless of what happens to the activity. This is the same reason that broadcast receivers shouldemploy services rather than simply put time-consuming operations in a thread.

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 tothe appropriate user interface widgets, including drawing events. It
is also the thread in whichyour 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 sometimescalled the UI
thread.

The system does not create a separate thread for each instance of a component. Allcomponents that run in the same process are instantiated in the UI thread, and system calls toeach component are dispatched from that thread. Consequently, methods
that respond to systemcallbacks (such as
onKeyDown()
to report user actionsor 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 thetouch event to the widget, which in turn sets its pressed state and posts an invalidate request tothe event queue. The UI thread dequeues the request and notifies
the widget that it should redrawitself.

When your app performs intensive work in response to user interaction, this single thread modelcan yield poor performance unless you implement your application properly. Specifically, ifeverything is happening in the UI thread, performing long operations
such as network access ordatabase queries will block the whole UI. When the thread is blocked, no events can be dispatched,including drawing events. From the user's perspective, theapplication 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 notresponding" (ANR) dialog. The user might then decide to quit your application
and uninstall itif they are unhappy.

Additionally, the Andoid UI toolkit is not thread-safe. So, you must not manipulateyour UI from a worker thread—you must do all manipulation to your user interface from the UIthread. 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 thread model described above, it's vital to the responsiveness of yourapplication's UI that you do not block the UI thread. If you have operations to performthat are not instantaneous, you should make sure to do them in separate threads
("background" or"worker" threads).

For example, below is some code for a click listener that downloads an image from a separatethread and displays it in an
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, this seems to work fine, because it creates a new thread to handle the networkoperation. However, it violates the second rule of the single-threaded model:do not access theAndroid UI toolkit from outside the UI thread—this sample modifies
the
ImageView
from the worker thread instead of the UI thread. This can result inundefined and unexpected behavior, which can be difficult and time-consuming to track down.

To fix this problem, Android offers several ways to access the UI thread from otherthreads. Here is a list of methods that can help:

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();
}


Now this implementation is thread-safe: the network operation is done from a separate threadwhile the
ImageView
is manipulated from the UI thread.

However, as the complexity of the operation grows, this kind of code can get complicated anddifficult to maintain. To handle more complex interactions with a worker thread, you might considerusing a
Handler
in your worker thread, to process
messages delivered from the UIthread. Perhaps the best solution, though, is to extend 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 work on your userinterface. It performs the blocking operations in a worker thread and then publishes the results onthe UI thread, without requiring you to handle threads and/or handlers yourself.

To use it, you must subclass
AsyncTask
and implement the
doInBackground()
callback method, which runs in a pool ofbackground threads. To update your UI, you should implement
onPostExecute()
, which delivers the result from
doInBackground()
and runs in the UI thread,
so you can safelyupdate your UI. You can then run the task by calling
execute()
from the UI thread.

For example, you can implement the previous example using
AsyncTask
thisway:

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 this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}

Now the UI is safe and the code is simpler, because it separates the work into thepart that should be done on a worker thread and the part that should be done on the UI thread.

You should read the
AsyncTask
reference for a full understanding onhow to use this class, but here is a quick overview of how it works:

You can specify the type of the parameters, the progress values, and the finalvalue of the task, using generics
The method
doInBackground()
executes automaticallyon a worker thread
onPreExecute()
,
onPostExecute()
, and
onProgressUpdate()
are all invoked on the UI thread
The value returned by
doInBackground()
is sent to
onPostExecute()

You can call
publishProgress()
at anytime in
doInBackground()
to execute
onProgressUpdate()
on the UI thread
You can cancel the task at any time, from any thread

Caution: Another problem you might encounter when using a workerthread is unexpected restarts in your activity due to aruntime configuration change(such as when the user changes the screen orientation), which may destroy
your worker thread. Tosee how you can persist your task during one of these restarts and how to properly cancel the taskwhen the activity is destroyed, see the source code for theShelves sample application.

Thread-safe methods

In some situations, the methods you implement might be called from more than one thread, andtherefore must be written to be thread-safe.

This is primarily true for methods that can be called remotely—such as methods in abound service. When a call on amethod 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 froma 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 theservice's process, methods implemented in the object that
onBind()
returns (for example, a subclass
that implements RPC methods) would be called from threadsin the pool. Because a service can have more than one client, more than one pool thread can engagethe 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 UIthread for the process. Because these methods might be called from any number of threads
at thesame 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 executedremotely (in another process), with any result returned back to thecaller.
This entails decomposing a method call and its data to a level the operating system canunderstand, transmitting it from the local process and address space to the remote process andaddress space, then reassembling and reenacting the call there. Return values
are thentransmitted in the opposite direction. Android provides all the code to perform these IPCtransactions, 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 theServices developer guide.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: