当一个应用组件开始运行时,而且该应用中没有其他的组件在运行时,安卓系统会为该应用打开一个linux进程,伴随着这个进程,还有一个单线程。也就是说,一个进程hold住应用,还伴随有一个单线程。默认情况下,同一个应用的所有组件运行在同一个进程中和同一个主线程。如果一个组件开始运行,在此之前同属于一个应用的其他组件事先已经开始运行,也就是这个应用的进程之前已经开始运行了,那么这个组件就在这个已有的进程中运行,而且还使用同一个主线程。即,一个应用的进程已经在运行,而其中某个组件一直没有运行,然后也开始运行了,那么该组件还是运行在已有的那个进程中。然而,你可以让应用中的不同组件运行在不同的进程中,然后再为每个这样的进程再创建额外的主线程。
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 memory is low and 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 rules 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, but eventually needs to remove old processes to reclaim memory for new or more important processes. To determine which processes to keep and which to kill, the system places each process into an "importance hierarchy" based on the components running in the process and the state of those components. Processes with the lowest importance are eliminated first, then those with the next lowest importance, and so on, as necessary to recover system resources.
There are five levels in the importance hierarchy. The following list presents the different types of processes in order of importance (the first process is most important and is killed 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 (theActivity
'sonResume()
method has been called). - It hosts a
Service
that's bound to the activity that the user is interacting with. - It hosts a
Service
that's running "in the foreground"—the service has calledstartForeground()
. - It hosts a
Service
that's executing one of its lifecycle callbacks (onCreate()
,onStart()
, oronDestroy()
). - It hosts a
BroadcastReceiver
that's executing itsonReceive()
method.
Generally, only a few foreground processes exist at any given time. They are killed only as a last resort—if memory is so low that they cannot all continue to run. Generally, at that point, the device has reached a memory paging state, so killing some foreground processes is required to keep the user interface responsive.
- It hosts an
- 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 still visible to the user (itsonPause()
method has been called). This might occur, for example, if the foreground activity started a dialog, which allows the previous 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 so is required to keep all foreground processes running.
- It hosts an
- 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 two higher categories. Although service processes are not directly tied to anything the user sees, they are generally doing things that the user cares about (such as playing music in the background or downloading data on the network), so the system keeps them running unless there's not enough memory to 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 direct impact on the user experience, and the system can kill them at any time to reclaim memory for a foreground, visible, or service process. Usually there are many background processes running, so they are kept in an LRU (least recently used) list to ensure that the process with the activity that was most recently seen by the user is the last to be killed. If an activity implements its lifecycle methods correctly, and saves its current state, killing its process will not have a visible effect on the user experience, because when the user navigates back to the activity, the activity restores all of its visible state. See the Activities document for information about saving and restoring state. - Empty process
A process that doesn't hold any active application components. The only reason to keep this kind of process alive is for caching purposes, to improve startup time the next time a component needs to run in it. The system often kills these processes in order to balance overall system resources between process caches and the underlying kernel caches.
Android ranks a process at the highest level it can, based upon the importance of the components currently active in the process. For example, if a process hosts a service and a visible activity, 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 on it—a process that is serving another process can never be ranked lower 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 is always considered at least as 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 a service for that operation, rather than simply 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 perform the 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 should employ 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 to the appropriate user interface widgets, including drawing events. It is also 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.
当一个应用已经开始运行了,系统会为该应用创建一个叫做主线程的线程。这个线程非常重要,因为它负责将事件分发到合适的用户界面控件,比如绘画事件。也正是通过在这个线程,你的应用与界面控件进行交互。所以呢,主线程有时候也被叫做UI线程。
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.
当你的应用为了响应用户操作,需要执行一些费时的工作时,这种单线程模型(就是主线程做的事情)可能会导致非常糟糕的体验,除非你能避免这个情况。具体而言,如果每件事情都在主线程中发生,比如执行一些像网络访问,数据库查询等需要长时间的操作,这将使得整个UI界面都会堵塞。当这个主线程被堵塞了,那么注入绘制事件等事件就没有人来分发给界面控件。安卓讲究的就是一个界面交互,现在主线程都在忙于费时操作,在这些费时操作没有完成之前,它又不能执行一些UI操作,就会导致UI僵在那。从用户的角度来看,应用似乎挂起了。更糟糕的是,如果主线程挂起的时间超过5秒钟,用户会被告知“应用没有响应”的对话框,用户也许会退出你的应用,不高兴的用户还会卸载你的应用。
Additionally, the Andoid 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:
另外,线程界面控件不是线程安全的。所以,千万不能通过非主线程的线程来操作UI界面,对于UI界面的一切操作只能通过主线程来完成。因此,对于安卓单线程模型而言,有两种处理方式:
- 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 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).
基于上述描述的单线程模型,千万不要阻塞主线程。如果你没有立即要完成的事情,可以将这些事情放在不同的线程中,即所谓的后台线程或者工作线程。
For example, below is some code for a click listener that downloads an image from a separate thread and displays it in an ImageView
:
比如,下面一段代码,演示 的是用户点击一个按钮,应用就可以在一个单独的线程中下载图片,并且在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 network operation. However, it violates the second rule of the single-threaded model: do not access the Android UI toolkit from outside the UI thread—this sample modifies the ImageView
from the worker thread instead of the UI thread. This can result in undefined and unexpected behavior, which can be difficult and time-consuming to track down.
首先,这段代码看上去似乎没啥问题,因为它创建了一个新的线程来处理网络操作。然而,这段代码违背了单线程模型的第二条原则,也就是不要再飞主线程的其他线程中操作界面控件。这段代码中,是在非主线程的线程中修改了ImageView,而不是在主线程中修改。这会导致没有定义的或者不可预知的错误,这种错误如果要跟踪的话将会是非常困难和费时的。我估计,主线程和单独线程一起更新UI界面的话,会引起冲突,也就是线程共享资源的问题,所以安卓不让非主线程的线程来操作界面。
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:
为了修正这个问题,安卓提供了几种方式,可以在非主线程的线程中访问界面。比如:
这些方式都是通过post将Runnable任务安排在主线程消息队列中;
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 thread while theImageView
is 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. 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.
然而,随着操作复杂度的提高,这类代码会变得越来越难以维护。为了处理工作线程中更为复杂的操作,你可以考虑在工作线程中使用Handler,来处理来自于主线程的消息。也许,最佳的解决方案是是扩展AsyncTask类,简化了工作线程的工作。
Using AsyncTask
AsyncTask
allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.
AsynvTask类允许你执行一些异步操作。它会在工作线程中执行一些耗时的操作,再把执行的结果发布给主线程,不需要你再做其他事情。
To use it, you must subclass AsyncTask
and implement the doInBackground()
callback method, which runs in a pool of background threads. To update your UI, you should implement onPostExecute()
, which delivers the result from doInBackground()
and runs in the UI thread, so you can safely update your UI. You can then run the task by calling execute()
from the UI thread.
为了使用这个类,你必须要继承AsynvTask,而且还要实现doInBackground这个方法,这个方式会在背景线程池中执行。然后,为了更新你的UI节目,你还要实现onPostExecute方法,这个方法会将结果从doInBackground方法中返回给主线程,所以你可以安全的更新UI界面。使用AsynvTask,你可以在主线程中,调用execute来调用。
For example, you can implement the previous example using AsyncTask
this way:
比如,你可以使用AsynvTask来完成之前的例子:
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 the part that should be done on a worker thread and the part that should be done on the UI thread.
现在UI操作时安全的了,代码也很简单,因为这个类会自动地将需要工作线程去完成事情让工作线程完成,需要主线程完成的事情让主线程完成。
You should read the AsyncTask
reference for a full understanding on how to use this class, but here is a quick overview of how it works:
下面我们队 AsyncTask
有一个快速的概览。
- You can specify the type of the parameters, the progress values, and the final value of the task, using generics
- 你可以使用泛型指定doInBackground中的参数。
- The method
doInBackground()
executes automatically on a worker thread - doInBackground会自动在工作线程中执行。
onPreExecute()
,onPostExecute()
, andonProgressUpdate()
are all invoked on the UI threadonPreExecute()
,onPostExecute()
, andonProgressUpdate()
会自动地在主线程中执行。- The value returned by
doInBackground()
is sent toonPostExecute()
-
doInBackground()
返回的值会发送到onPostExecute()
- You can call
publishProgress()
at anytime indoInBackground()
to executeonProgressUpdate()
on the UI thread - 在主线程中,你可以在doInBackground方法中的任何时候调用
publishProgress
方法来执行onProgressUpdate
函数。 - You can cancel the task at any time, from any thread
- 你可以通过任何线程,在任何时候来取消任务。
Caution: Another problem you might encounter when using a worker thread is unexpected restarts in your activity due to a runtime configuration change (such as when the user changes the screen orientation), which may destroy your worker thread. To see how you can persist your task during one of these restarts and how to properly cancel the task when the activity is destroyed, see the source code for the Shelves sample application.
警告:在使用工作线程时,你可能遇到的另外一个问题,就是用户改变屏幕的方向,这会销毁你的工作线程。那么,在活动被销毁时,你该如何处理任务,可以看看源码Shelves作为参考。
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 theIBinder
(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 theContentResolver
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.
安卓使用远程过程调用这么一个机制,来跨进程通信(IPC)。也就是,一个进程A中的活动,或者其他组件,调用了B进程中的一个方法,那么该方法在B进程中执行,将执行的结果返回给A进程中的调用者。
To perform IPC, your application must bind to a service, using bindService()
. For more information, see theServices developer guide.