`

Android Dev Guide 中文版二 (原创,转载请注明出处)未完待续

阅读更多

 

进程和线程Processes and Threads

当应用组件需要第一次运行的时候,Android为此开启一个Linux进程带这一个可执行的线程。默认的,所有的应用组件都运行在进程和线程中。

然而,你能让组件在其他进程中运行,也可以为进程创建其他的线程。

进程

组件在哪个进程中运行是由清单文件来控制的,这些组件元素-<activity>, <service>, <receiver>, 和 <provider>-每个都有一个指定这个组件应该在哪个进程里运行的进程属性。这些属性可以被设定以至于每个组件运行在他们自己的进程里,或者也可以多个组件共享一个进程而其他组件不共享。他们也能被设定以至于不同应用的组件运行在同一个进程里,这些应用共享相同的Linux用户ID并且被签名通过相同的授权。<application>元素也有一个进程属性,为了给所有组件设定默认的值。

所有组件被实力化在指定进程的主线程中。并且系统从线程中调用被派遣到的组件。不同的线程被创建给每个实力。因此,响应这些调用的函数,这些函数例如View.onKeyDown() 报告用户动作和这个生命周期的通知,一会即将讨论在 Component Lifecycles 这一章节-总是运行在进程的主线程中。这意味着没有组件可以执行长操时间的或阻止操作(像网络连接操作或者计算循环)当被调用通过系统,如果这样就会阻止系统中的其他组件。你能为长时间的或阻碍操作创建一个分离的线程,这会在接下来讨论。

在一些点,Android可以决定关闭一个进程。当内存不够或者其他要马上响应用户的进程需要内存的时候。运行在进程里的应用组件因此被销毁。当他们再一次为这些组件工作时,一个进程将被这些组件重新启动。

当决定哪个进程结束时,android会权衡他们对于用户的重要性。例如,他更准备好关闭一个在屏幕上不在可见activities进程比一个可见的activities进程。决定是否结束一个进程,依赖组件在进程中的运行状态。这些状态是下一个章节的题目,组件的生命周期Component Lifecycles。 

线程Threads

即使你可以定义你的应用在一个单独的进程内运行。你你经常需要产生一个新的在后台工作的线程。自从用户接口必须总是迅速的相应用户的动作时,寄存在activity的线程也不应该有耗时的操作如网络下载。任何有可能不能迅速被完成的操作应该被分配给不同的线程。

线程用标准的java代码-java Thread被创建。android提供许多方便的类为管理线程-Looper为了运行一个带有线程消息循环,Handler为了产生消息,HandlerThread为了建立一个有消息循环的线程。

 

远程过程调用Remote procedure calls

 

Android有一个轻量的机制为远程过程调用-在本地一个方法被调用,但是执行在远程(另外一个进程),任何结果返回给调用者。这需要分解方法调用和所有他相关的数据变成一个操作系统能理解的级别。从本地进程和地址空间传输它给远程的进程和地址空间。并且重新组装和重新制定调用。返回值不得不被传输按照相关反方向。Android提供了所有的代码来做这件事,所以你能专注于定义和实现RPC接口。

一个RPC接口只能包括方法。所有的方法被同步执行(本地的方法停止不动直到远程方法返回结果),甚至它没有返回值。

简而言之,工作机制如下:开始通过用一个简单的IDL(接口定义语言)声明你想实现的RPC接口。从那个声明,这个aidl工具生成一个java接口定义,这个定义必须对于本地和远程进程都可见。它包括两个内部类,像下面展示的图片:

 

RPC mechanism.

 

这些内部类有所有的代码用来管理远程过程调用你用IDL声明的接口。这两个内部类实现IBinder接口,其中一个通过系统做本地的和内部的使用;你写的代码可以忽略它。另外,我们称为Stub,扩展了Binder。除了内部代码为了完成IPC调用,它包括在你定义在RPC接口中的方法声明。你用子类来实现这些方法,就像图标中的展示。

特别的,这个远程进程会被一个服务管理(因为服务能将进程和他连接的进程通知给系统),你会有两个接口文件通过aidl工具生成并且这个Stub子类实现RPC方法。服务的客户端会有一个接口文件通过aidl工具生成。

这是怎么样一个服务和他的客户端建立:

 

  • 服务的客户端(在本地端)会实现onServiceConnected() 和 onServiceDisconnected() 方法所以当一个成功的远程服务连接被建立他们能被通知,当断开他们也能被通知。他们随后会调用bindService() 来建立连接。
  • 服务端的onBind() 方法会被实现成或者接受连接或者拒绝连接。依靠它受到了intent( 传递给bindService()的intent)。如果连接被接受,它返回一个Stub子类的实例。
  • 如果服务接受连接,Android调用客户端的 onServiceConnected() 方法并且传递给他一个IBinder 对象, 通过服务来管理Stub自来的代理,通过代理,客户端可以调用远程服务。

这个简短的描述展示了RPC机制的一些细节。更过信息请看Designing a Remote Interface Using AIDLIBinder 类的描述.

线程安全方法Thread-safe methods

在一些上下文中,你实现的这个方法会被多个线程调用,并且必须写成线程安全的。

对于方法首要的准则是能被远程调用----就是上一章我们讨论的RPC机制。当在同一个进程中调用一个实现IBinder对象的方法就像调用IBinder一样。这个方法在调用者的线程中执行。然而,当这个调用在另外一个进程中

In a few contexts, the methods you implement may 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 — as in the RPC mechanism discussed in the previous section. When a call on a method implemented in an IBinder object originates in the same process as the IBinder, 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 Android maintains in the same process as the IBinder; it's not executed in the main thread of the process. For example, whereas a service's onBind() method would be called from the main thread of the service's process, methods implemented in the object that onBind() returns (for example, a Stub subclass that implements RPC methods) would be called from threads in the pool. Since services 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 main thread of the process. Since these methods may be called from any number of threads at the same time, they too must be implemented to be thread-safe.

Component Lifecycles

Application components have a lifecycle — a beginning when Android instantiates them to respond to intents through to an end when the instances are destroyed. In between, they may sometimes be active or inactive,or, in the case of activities, visible to the user or invisible. This section discusses the lifecycles of activities, services, and broadcast receivers — including the states that they can be in during their lifetimes, the methods that notify you of transitions between states, and the effect of those states on the possibility that the process hosting them might be terminated and the instances destroyed.

Activity lifecycle

An activity has essentially three states:

  • It is active or running when it is in the foreground of the screen (at the top of the activity stack for the current task). This is the activity that is the focus for the user's actions.
  • It is paused if it has lost focus but is still visible to the user. That is, another activity lies on top of it and that activity either is transparent or doesn't cover the full screen, so some of the paused activity can show through. A paused activity is completely alive (it maintains all state and member information and remains attached to the window manager), but can be killed by the system in extreme low memory situations.

  • It is stopped if it is completely obscured by another activity. It still retains all state and member information. However, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.

If an activity is paused or stopped, the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process. When it is displayed again to the user, it must be completely restarted and restored to its previous state.

As an activity transitions from state to state, it is notified of the change by calls to the following protected methods:

void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()

All of these methods are hooks that you can override to do appropriate work when the state changes. All activities must implement onCreate() to do the initial setup when the object is first instantiated. Many will also implement onPause() to commit data changes and otherwise prepare to stop interacting with the user.

Taken together, these seven methods define the entire lifecycle of an activity. There are three nested loops that you can monitor by implementing them:

  • The entire lifetime of an activity happens between the first call to onCreate() through to a single final call to onDestroy(). An activity does all its initial setup of "global" state in onCreate(), and releases all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().
  • The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). During this time, the user can see the activity on-screen, though it may not be in the foreground and interacting with the user. Between these two methods, you can maintain resources that are needed to show the activity to the user. For example, you can register a BroadcastReceiver in onStart() to monitor for changes that impact your UI, and unregister it in onStop() when the user can no longer see what you are displaying. The onStart() and onStop() methods can be called multiple times, as the activity alternates between being visible and hidden to the user.

  • The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time, the activity is in front of all other activities on screen and is interacting with the user. An activity can frequently transition between the resumed and paused states — for example, onPause() is called when the device goes to sleep or when a new activity is started, onResume() is called when an activity result or a new intent is delivered. Therefore, the code in these two methods should be fairly lightweight.

The following diagram illustrates these loops and the paths an activity may take between states. The colored ovals are major states the activity can be in. The square rectangles represent the callback methods you can implement to perform operations when the activity transitions between states.

 

State diagram for an Android activity lifecycle.

The following table describes each of these methods in more detail and locates it within the activity's overall lifecycle:

Method Description Killable? Next
onCreate() Called when the activity is first created. This is where you should do all of your normal static set up — create views, bind data to lists, and so on. This method is passed a Bundle object containing the activity's previous state, if that state was captured (see Saving Activity State, later).

Always followed by onStart().

No onStart()
     onRestart() Called after the activity has been stopped, just prior to it being started again.

Always followed by onStart()

No onStart()
onStart() Called just before the activity becomes visible to the user.

Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes hidden.

No onResume()
or
onStop()
     onResume() Called just before the activity starts interacting with the user. At this point the activity is at the top of the activity stack, with user input going to it.

Always followed by onPause().

No onPause()
onPause() Called when the system is about to start resuming another activity. This method is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, and so on. It should do whatever it does very quickly, because the next activity will not be resumed until it returns.

Followed either by onResume() if the activity returns back to the front, or by onStop() if it becomes invisible to the user.

Yes onResume()
or
onStop()
onStop() Called when the activity is no longer visible to the user. This may happen because it is being destroyed, or because another activity (either an existing one or a new one) has been resumed and is covering it.

Followed either by onRestart() if the activity is coming back to interact with the user, or by onDestroy() if this activity is going away.

Yes onRestart()
or
onDestroy()
onDestroy() Called before the activity is destroyed. This is the final call that the activity will receive. It could be called either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method. Yes nothing

Note the Killable column in the table above. It indicates whether or not the system can kill the process hosting the activity at any time after the method returns, without executing another line of the activity's code. Three methods (onPause(), onStop(), and onDestroy()) are marked "Yes." Because onPause() is the first of the three, it's the only one that's guaranteed to be called before the process is killed — onStop() and onDestroy() may not be. Therefore, you should use onPause() to write any persistent data (such as user edits) to storage.

Methods that are marked "No" in the Killable column protect the process hosting the activity from being killed from the moment they are called. Thus an activity is in a killable state, for example, from the time onPause() returns to the time onResume() is called. It will not again be killable until onPause() again returns.

As noted in a later section, Processes and lifecycle, an activity that's not technically "killable" by this definition might still be killed by the system — but that would happen only in extreme and dire circumstances when there is no other recourse.

Saving activity state

When the system, rather than the user, shuts down an activity to conserve memory, the user may expect to return to the activity and find it in its previous state.

To capture that state before the activity is killed, you can implement an onSaveInstanceState() method for the activity. Android calls this method before making the activity vulnerable to being destroyed — that is, before onPause() is called. It passes the method a Bundle object where you can record the dynamic state of the activity as name-value pairs. When the activity is again started, the Bundle is passed both to onCreate() and to a method that's called after onStart(), onRestoreInstanceState(), so that either or both of them can recreate the captured state.

Unlike onPause() and the other methods discussed earlier, onSaveInstanceState() and onRestoreInstanceState() are not lifecycle methods. They are not always called. For example, Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key). In that case, the user won't expect to return to the activity, so there's no reason to save its state.

Because onSaveInstanceState() is not always called, you should use it only to record the transient state of the activity, not to store persistent data. Use onPause() for that purpose instead.

Coordinating activities

When one activity starts another, they both experience lifecycle transitions. One pauses and may stop, while the other starts up. On occasion, you may need to coordinate these activities, one with the other.

The order of lifecycle callbacks is well defined, particularly when the two activities are in the same process:

  1. The current activity's onPause() method is called.
  2. Next, the starting activity's onCreate(), onStart(), and onResume() methods are called in sequence.
  3. Then, if the starting activity is no longer visible on screen, its onStop() method is called.

Service lifecycle

A service can be used in two ways:

  • It can be started and allowed to run until someone stops it or it stops itself. In this mode, it's started by calling Context.startService() and stopped by calling Context.stopService(). It can stop itself by calling Service.stopSelf() or Service.stopSelfResult(). Only one stopService() call is needed to stop the service, no matter how many times startService() was called.
  • It can be operated programmatically using an interface that it defines and exports. Clients establish a connection to the Service object and use that connection to call into the service. The connection is established by calling Context.bindService(), and is closed by calling Context.unbindService(). Multiple clients can bind to the same service. If the service has not already been launched, bindService() can optionally launch it.

The two modes are not entirely separate. You can bind to a service that was started with startService(). For example, a background music service could be started by calling startService() with an Intent object that identifies the music to play. Only later, possibly when the user wants to exercise some control over the player or get information about the current song, would an activity establish a connection to the service by calling bindService(). In cases like this, stopService() will not actually stop the service until the last binding is closed.

Like an activity, a service has lifecycle methods that you can implement to monitor changes in its state. But they are fewer than the activity methods — only three — and they are public, not protected:

void onCreate()
void onStart(Intent intent)
void onDestroy()

By implementing these methods, you can monitor two nested loops of the service's lifecycle:

  • The entire lifetime of a service happens between the time onCreate() is called and the time onDestroy() returns. Like an activity, a service does its initial setup in onCreate(), and releases all remaining resources in onDestroy(). For example, a music playback service could create the thread where the music will be played in onCreate(), and then stop the thread in onDestroy().
  • The active lifetime of a service begins with a call to onStart(). This method is handed the Intent object that was passed to startService(). The music service would open the Intent to discover which music to play, and begin the playback.

    There's no equivalent callback for when the service stops — no onStop() method.

The onCreate() and onDestroy() methods are called for all services, whether they're started by Context.startService() or Context.bindService(). However, onStart() is called only for services started by startService().

If a service permits others to bind to it, there are additional callback methods for it to implement:

IBinder onBind(Intent intent)
boolean onUnbind(Intent intent)
void onRebind(Intent intent)

The onBind() callback is passed the Intent object that was passed to bindService and onUnbind() is handed the intent that was passed to unbindService(). If the service permits the binding, onBind() returns the communications channel that clients use to interact with the service. The onUnbind() method can ask for onRebind() to be called if a new client connects to the service.

The following diagram illustrates the callback methods for a service. Although, it separates services that are created via startService from those created by bindService(), keep in mind that any service, no matter how it's started, can potentially allow clients to bind to it, so any service may receive onBind() and onUnbind() calls.

State diagram for Service callbacks.

Broadcast receiver lifecycle

A broadcast receiver has single callback method:

void onReceive(Context curContext, Intent broadcastMsg)

When a broadcast message arrives for the receiver, Android calls its onReceive() method and passes it the Intent object containing the message. The broadcast receiver is considered to be active only while it is executing this method. When onReceive() returns, it is inactive.

A process with an active broadcast receiver is protected from being killed. But a process with only inactive components can be killed by the system at any time, when the memory it consumes is needed by other processes.

This presents a problem when the response to a broadcast message is time consuming and, therefore, something that should be done in a separate thread, away from the main thread where other components of the user interface run. If onReceive() spawns the thread and then returns, the entire process, including the new thread, is judged to be inactive (unless other application components are active in the process), putting it in jeopardy of being killed. The solution to this problem is for onReceive() to start a service and let the service do the job, so the system knows that there is still active work being done in the process.

The next section has more on the vulnerability of processes to being killed.

Processes and lifecycles

The Android system tries to maintain an application process for as long as possible, but eventually it will need to remove old processes when memory runs low. To determine which processes to keep and which to kill, Android places each process into an "importance hierarchy" based on the components running in it and the state of those components. Processes with the lowest importance are eliminated first, then those with the next lowest, and so on. There are five levels in the hierarchy. The following list presents them in order of importance:

  1. A foreground process is one 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 hold:
    • It is running an activity that the user is interacting with (the Activity object's onResume() method has been called).
    • It hosts a service that's bound to the activity that the user is interacting with.

    • It has a Service object that's executing one of its lifecycle callbacks (onCreate(), onStart(), or onDestroy()).

    • It has a BroadcastReceiver object that's executing its onReceive() method.

    Only a few foreground processes will 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.

  2. A visible process is one 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 holds:

    • It hosts an activity that is not in the foreground, but is still visible to the user (its onPause() method has been called). This may occur, for example, if the foreground activity is a dialog that allows the previous activity to be seen behind it.
    • It hosts a service that's bound to a visible activity.

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

  3. A service process is one that is running a service that has been started with the startService() method and that 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 an mp3 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.

  4. A background process is one holding an activity that's not currently visible to the user (the Activity object's onStop() method has been called). These processes have no direct impact on the user experience, and can be killed 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 captures its current state, killing its process will not have a deleterious effect on the user experience.

  5. An empty process is one that doesn't hold any active application components. The only reason to keep such a process around is as a cache 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 will be ranked as a visible process, not a service process.

In addition, a process's ranking may 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 will always be considered at least as important as process B.

Because a process running a service is ranked higher than one with background activities, an activity that initiates a long-running operation might do well to start a service for that operation, rather than simply spawn a thread — particularly if the operation will likely outlast the activity. Examples of this are playing music in the background and uploading a picture taken by the camera to a web site. Using a service guarantees that the operation will have at least "service process" priority, regardless of what happens to the activity. As noted in the Broadcast receiver lifecycle section earlier, this is the same reason that broadcast receivers should employ services rather than simply put time-consuming operations in a thread.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics