1.5 应用程序的生命周期
应用程序的生命周期是指进程在Android系统中从启动到终止的所有阶段,也就是Android程序启动到停止的全过程。程序的生命周期由Android系统进行调试和控制。了解Android的生命周期是学习Android应用程序开发的基础。
在Android系统中,当某个Activity调用startActivity(myIntent) 时,系统会在所有已经安装的程序中寻找其intent filter和myIntent最匹配的一个Activity,启动这个进程,并把这个intent通知给这个Activity。这就是一个程序的“生”。例如,在Home application中选择“Web browser”,系统会根据这个intent找到并启动Web browser程序,显示Web browser的一个Activity用于浏览网页(这个启动过程有点类似在计算机上双击桌面上的一个图标,启动某个应用程序)。在Android中,所有的应用程序“生来就是平等的”,所以不光Android的核心程序甚至第三方程序也可以发出一个intent来启动另外一个程序中的一个Activity。Android的这种设计非常有利于“程序部件”的重用。
1.5.1 进行优先级
一个Android程序的进程是何时被系统结束的呢?通俗地说,一个即将被系统关闭的程序是系统在内存不足(low memory)时,根据“重要性层次”选出来的“牺牲品”。一个进程的重要性是根据其中运行的部件和部件的状态决定的。各种进程按照重要性从高到低排列,如图1-32所示。
图1-32 Android进程优先级效果图
1.前台进程
前台进程是与用户正在交互的进程,也是Android系统中最重要的进程。处于前台进程一般包含以下四种情况。
● 进行中的Activity正在与用户进行交互。
● 进程服务被Activity调用,而且这个Activity正在与用户进行交互。
● 进程服务正在执行生命周期中的回调函数,如onCreate()、onStart()或onDestroy()。
● 进程的BroadcastReceiver正在执行onReceive()函数。
Android系统为多任务操作系统,当系统中的多个前台进程同时运行时,如果出现资源不足的情况,此时Android内核将自动清除部分前台进程,保证最主要的用户界面能够及时响应操作。
2.可见进程
可见进程是指在屏幕上显示,但不在前台的程序。例如,一个前台进程以对话框的形式显示在该进程前面。这样的进程也很重要,它们只有在系统没有足够内存运行所有前台进程时,才会被结束。
3.服务进程
服务进程在后台持续运行,如后台音乐播放、后台数据上传/下载等。这样的进程对用户来说一般很有用,所以只有当系统没有足够内存来维持所有的前台进程和可见进程时,才会被结束。
4.后台进程
后台进程程序拥有一个用户不可见的Activity。这样的程序在系统内存不足时,按照LRU的顺序被结束。
5.空进程
空进程不包含任何活动的程序部件,系统可能随时关闭这类进程。
从某种意义上讲,垃圾收集机制把程序员从“内存管理噩梦”中解放出来,而Android的进程生命周期管理机制把用户从“任务管理噩梦”中解放出来。笔者见过一些Nokia S60用户和Windows Mobile用户,要么因为长期不关闭多余的应用程序而导致系统变慢,要么因为不时查看应用程序列表而影响使用体验。Android使用Java作为应用程序API,并且结合其独特的生命周期管理机制,同时为开发者和使用者提供最大程度的便利。
1.5.2 Activity的生命周期
Activity的生命周期是指应用程序的Activity从启动到销毁的全过程。Activity的生命周期是在Android应用程序设计中最重要的内容,直接关系到用户程序的界面和功能。
1.活动栈
每一个活动的状态是由它在活动栈中所处的位置所决定的,活动栈是当前所有正在运行的进程的后进先出的集合。当一个新的活动启动时,当前的前台屏幕就会移动到栈顶。如果用户使用Back(返回)按钮返回到了刚才的活动,或者前台活动被关闭了,那么栈中的下一个活动就会移动到栈顶,变为活动状态。图1-33说明了这个过程。
图1-33 活动栈流程图
2.Activity的状态
随着活动的创建和销毁,它们会按照图1-33所示的那样,从栈中移进移出。在这个过程中,它们也经历了活动、暂停、停止和非活动4种可能的状态,如图1-34所示。
图1-34 Activity的状态
(1)活动状态:当一个活动位于栈顶的时候,它是可见的、被关注的前台活动,这时它可以接收用户输入。Android将会不惜一切代价来保持它处于活动状态,并根据需要来销毁栈下面部分的活动,以保证这个活动拥有它所需要的资源。当另一个活动变为活动状态时,这个活动就将被暂停。
(2)暂停状态:在某些情况下,活动是可见的,但是没有被关注,此时它就处于暂停状态。当一个透明的或者非全屏的活动位于某个处于活动状态的活动之前时,这个透明的或者非全屏的活动就会达到这个状态。当活动被暂停的时候,它仍然会被当做近似于活动状态的状态,但是它不能接收用户的输入事件。在极端情况下,当一个活动变得完全不可见的时候,它就会变为停止状态。
(3)停止状态:当一个活动不可见的时候,它就处于停止状态。此时,活动仍然会停留在内存中,保存所有的状态和成员信息,然而当系统的其他地方要求使用内存的时候,它们就会成为被清除的首要候选对象。在一个活动停止的时候,保存数据和当前的UI状态是很重要的。一旦一个活动被退出或者关闭,它就会变为非活动状态。
(4)非活动状态:当一个活动被销毁之后,在它启动之前就处于非活动状态。处于非活动状态的活动已经从活动栈中移除了,因此,在它们可以被显示和使用之前,需要被重新启动。
在Android系统中,采用“栈”结构来管理Activity,这是一种“后进先出”的原则,如图1-35所示。当一个Activity被启用时,将执行入栈操作。位于栈顶的Activity处于活动状态,其他Activity则处于暂停状态或者停止状态。当Activity关闭时,将执行出栈操作,从而变成非活动状态。当Android系统资源紧张时,Android内核也会终止部分长久没有响应的Activity,使之为非活动状态,从而释放系统资源。
图1-35 Activity的栈结构
3.管理Activity的生命周期
在Activity系统中,一般通过Activity的事件回调函数来管理Activity的生命周期。这些事件回调函数如下:
public class MyActivity extends Activity { void onCreate(Bundle savedInstanceState); void onStart(); void onRestart(); void onResume(); void onPause(); void onStop(); void onDestroy(); }
这些Activity生命周期的事件回调函数将会被Android系统自动调用。用户也可以重载这些事件回调函数来完成自己的操作。Activity生命周期的事件回调函数的说明如表1-3所示。
表1-3 Activity生命周期的事件回调函数
在Android系统中,Activity的生命周期,以及各个事件回调函数之间的跳转,如图1-36所示。
图1-36 Activity的生命周期
另外,当由于系统资源紧张时,Activity可能会被终止。此时,Android提供了相应的状态保存/恢复的事件回调函数,如表1-4所示。
表1-4 Activity状态保存/恢复的事件回调函数
1.5.3 Activity生命周期调用顺序
一般来说,Activity的生命周期可分为全生命周期、可视生命周期和活动生命周期三类。每种生命周期中包含不同的事件回调函数,各个事件回调函数的调用顺序也不同,如图1-37所示。
图1-37 Activity生命周期的调用顺序图
对于Activity全生命周期,事件回调函数的调用顺序为onCreate()→onStart()→onResume()→onPause()→onStop()→onDestroy()。每一步调用的含义如下:
● 调用onCreate()函数分配资源。
● 调用onStart()将Activity显示在屏幕上。
● 调用onResume()获取屏幕焦点。
● 调用onPause()、onStop和onDestroy(),释放资源并销毁进程。
对于Activity可视生命周期,事件回调函数的调用顺序为onSaveInstanceState()→onPause()→onStop()→onRestart()→onStart()→onResume()。每一步调用的含义如下:
● 调用onSaveInstanceState()函数保存Activity状态。
● 调用onPause()和onStop(),停止对不可见Activity的更新。
● 调用onRestart()恢复界面上需要更新的信息。
● 调用onStart()和onResume()重新显示Activity,并接受用户交互。
对于活动生命周期,事件回调函数的调用顺序为onSaveInstanceState()→onPause()→onResume()。每一步调用的含义如下:
● 调用onSaveInstanceState()保存Activity的状态。
● 调用onPause()停止与用户交互。
● 调用onResume()恢复与用户的交互。
1.5.4 Service的生命周期
Service生命周期一般有两种使用方式。
Service可以被启动或者允许被启动直到有人停止了它或者它自己停止了。在这种模式下,它通过Context.startService()方法开始,通过Context.stopService()方法停止。它可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己。只要调用一次stopService()方法便可以停止服务,无论调用了多少次的启动服务方法。
Service可以通过定义好的接口来编程,客户端建立一个与Service的链接,并使用此链接与Service进行通话。通过Context.bindService()方法来绑定服务,通过Context.unbindService()方法来关闭服务。多个客户端可以绑定同一个服务。如果Service还未被启动,bindService()方法可以启动服务。
这两种模式是完全独立的。你可以绑定一个已经通过startService()方法启动的服务。例如,一个后台播放音乐服务可以通过startService()和一个intend对象来播放音乐。可能用户在播放过程中要执行一些操作,例如,获取歌曲的一些信息,此时Activity可以通过调用bindServices()方法与Service建立连接。这种情况下,stopServices()方法实际上不会停止服务,直到最后一次绑定关闭。
像一个Activity那样,Service服务也有生命周期,也提供了事件回调函数:void onCreate()、void onStart(Intent intent)、void onDestroy()。
通过实现这三个生命周期方法,可以监听Service的两个嵌套循环的生命周期。
1.Service整个生命周期
Service整个生命周期是在onCreate()和onDestroy()方法之间。和Activity一样,在onCreate()方法里初始化,在onDestroy()方法里释放资源。例如,一个背景音乐播放服务可以在onCreate()方法里播放,在onDestroy()方法里停止。
2.Service活动生命周期
Service活动生命周期是在onStart()之后,这个方法会处理通过startServices()方法传递来的intent对象。音乐Service可以通过intent对象来找到要播放的音乐,然后开始后台播放。
Service停止时没有相应的回调方法,即没有onStop()方法。onCreate()方法和onDestroy()方法针对的是所有的Service,无论它们是否启动。然而,只有通过startService()方法启动的Service才会被调用onStart()方法。如果一个Service允许其他命令绑定,那么需要实现以下额外的方法:
IBinder onBind(Intent intent) boolean onUnbind(Intent intent) void onRebind(Intent intent)
onBind()回调方法会继续传递通过bindService()传递来的intent对象。onUnbind()会处理传递给unbindService()的intent对象。如果Service允许绑定,onBind()会返回客户端与服务互相联系的通信频道。如果建立了一个新的客户端与服务的链接,onUnbind()方法可以请求调用onRebind()方法。
1.5.5 Android生命周期综合实例
下面通过用Java代码来完成Android生命周期,其完整代码如下:
import android.app.Activity; import android.os.Bundle; public class MyActivity extends Activity { // 在完整生存期开始的时候调用 @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // 初始化一个活动 } // 在onCreate方法完成之后调用,用来恢复UI状态 @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); //从savedInstanceState中恢复UI状态 // 这个bundle也被传递给onCreate } // 在一个活动进程的后续的可见生存期之前调用 @Override public void onRestart() { super.onRestart(); // 当知道这个进程中的活动已经可见之后,载入改变 } // 在可见生存期开始时调用 @Override public void onStart() { super.onStart(); // 既然活动可见,就应用任何要求的UI改变 } // 在活动状态生存期开始时调用 @Override public void onResume() { super.onResume(); //恢复活动所需要的任何暂停的UI更新、线程或者进程,但是当不活动 //的时候,就挂起它们 } // 在活动状态生存期结束的时候调用,用来保存UI状态改变 @Override public void onSaveInstanceState(Bundle savedInstanceState) { //把UI状态改变保存到savedInstanceState //如果进程被销毁或者重启,那么这个bundle将被传递给 //onCreate super.onSaveInstanceState(savedInstanceState) } // 在活动状态生存期结束时调用 @Override public void onPause() { //当活动不是前台的活动状态的活动时,挂起不需要更新的UI更新、 //线程或者CPU密集的进程 super.onPause(); } // 在可见生存期结束时调用 @Override public void onStop() { // 当进程不可见的时候,挂起不需要的剩下的UI更新、线程或者处理, // 保存所有的编辑或者状态改变,因为这个进程可能会被销毁(从而为 // 其他进程释放资源) super.onStop(); } // 在完整生存期结束时调用 @Override public void onDestroy() { // 清空所有的资源,包括结束线程、关闭数据库链接等 super.onDestroy(); } }