6.1 Android程序的生命周期

Android是一构建在Linux之上的开源移动开发平台,里面的每个程序都各自独立运行在Linux进程中。当一个程序或其某些部分被请求时,它的进程就“出生”了。当这个程序没有必要再运行下去且系统需要回收这个进程的内存用于其他程序时,这个进程就“死亡”了。由此可以看出,Android程序的生命周期是由系统控制而非程序自身直接控制。要想编写好某种类型的程序,或者完成某种平台下的程序开发工作,最关键的就是要弄清楚这种类型的程序或整个平台下的程序的一般工作模式,并且要熟记在心。在Android系统中,程序的生命周期控制就是属于这个范畴。在本节的内容中,将详细讲解Android程序的生命周期的基本知识。

6.1.1 进程和线程

当第一次运行某个组件的时候,Android就启动了一个进程。在默认情况下,所有的组件和程序运行在这个进程和线程中。当然,也可以设置组件在其他的进程或者线程中运行。

在Android系统中,由manifest file控制组件运行的进程。在组件的节点<ctivity>, <service>,<receiver>和<provider>中都包含一个process属性,通过这个属性可以设置组件运行的进程。

可以配置组件在一个独立进程运行,或者多个组件在同一个进程运行。

如果这些程序共享一个User ID并给定同样的权限,可以让多个程序在一个进程中运行。

另外,在<application>节点中也包含了process属性,用来设置程序中所有组件的默认进程。

所有的组件在此进程的主线程中实例化,系统对这些组件的调用从主线程中分离。并非每个对象都会从主线程中分离。一般来说,响应例如View.onKeyDown()用户操作的方法和通知的方法也在主线程中运行。这说明当组件被系统调用时,不应该长时间运行或者阻塞操作(如网络操作或者计算大量数据),因为这样会阻塞进程中的其他组件。此时可以把这类操作从主线程中分离出来。当更加常用的进程无法获取足够内存时,Android可能会关闭这些不常用的进程。当下次启动程序时,会重新启动这些进程。

当决定哪个进程需要被关闭的时候,Android会考虑哪个对用户更加有用。如Android会倾向于关闭一个长期不显示在界面的进程来支持一个经常显示在界面的进程。是否关闭一个进程决定于组件在进程中的状态。

即使为组件分配了不同的进程,有时候也需要再重新分配线程。比如用户界面需要很快对用户进行响应,因此某些费时的操作,如网络连接、下载或者非常占用服务器时间的操作应该放到其他线程。

在Android中提供了很多方便的管理线程的方法,例如通过Looper在线程中运行一个消息循环,使用Handler传递一个消息,使用HandlerThread创建一个带有消息循环的线程。

6.1.2 进程的类型

开发者必须理解不同的应用程序组件,尤其是Activity、Service和Intent Receiver。了解这些组件是如何影响应用程序的生命周期的,这非常重要。如果不正确地使用这些组件,可能会导致系统终止正在执行重要任务的应用程序进程。

在Android系统中,根据进程中当前处于活动状态组件的重要程度为依据对进程进行分类。进程的优先级可能也会根据该进程与其他进程的依赖关系而增长。例如,如果进程A通过在进程B中设置Context.BIND_AUTO_CREATE标记或使用ContentProvider被绑定到一个服务(Service),那么进程B在分类时至少要被看成与进程A同等重要。Android系统中的进程的类型被分为如下5种。

(1)前台进程(Foreground)。

与用户当前正在做的事情密切相关。不同的应用程序组件能够通过不同的方法将它的宿主进程移到前台。在如下任何一个条件下:进程正在屏幕的最前端运行一个与用户交互的活动(Activity),它的onResume()方法被调用;或进程有一正在运行的Intent Receiver(它的Intent Receiver.onReceive()方法正在执行);或进程有一个服务(Service),并且在服务的某个回调函数(Service.onCreate()、Service.onStart()或Service.onDestroy())内有正在执行的代码,系统将把进程移动到前台。

(2)可见进程(Visible)。

它有一个可以被用户从屏幕上看到的活动,但不在前台(它的onPause()方法被调用)。例如,如果前台的活动是一个对话框,以前的活动就隐藏在对话框之后,就会现这种进程。可见进程非常重要,一般不允许被终止,除非是为了保证前台进程的运行而不得不终止它。

(3)服务进程(Service)。

拥有一个已经用startService()方法启动的服务。虽然用户无法直接看到这些进程,但它们做的事情却是用户所关心的(如后台MP3回放或后台网络数据的上传下载)。因此,系统将一直运行这些进程,除非内存不足以维持所有的前台进程和可见进程。

(4)后台进程(Background)。

拥有一个当前用户看不到的活动(它的onStop()方法被调用)。这些进程对用户体验没有直接的影响。如果它们正确执行了活动生命周期,系统可以在任意时刻终止该进程以回收内存,并提供给前面3种类型的进程使用。系统中通常有很多这样的进程在运行,因此要将这些进程保存在LRU列表中,以确保当内存不足时用户最近看到的进程最后一个被终止。

(5)空进程(Empty)。

不拥有任何活动的应用程序组件的进程。保留这种进程的唯一原因是在下次应用程序的某个组件需要运行时,不需要重新创建进程,这样可以提高启动速度。