Activity生命周期
维护一个 Activity 的生命周期非常重要,因为 Activity 随时会被系统回收掉。
生命周期:
现在使用者使用智慧型手机,大多已习惯使用多工 (Multi-Task) 的操作系统 ( 如 Window sMobile),可以在用手机听音乐的同时,也执行其他多个程序。同时执行多个程序有它的明显好处,但是也有它的严重的缺点。每多执行一个应用程序,就会多耗费一些系统记忆体 。而手机里的记忆体是相当有限的。当同时执行的程序过多,或是关闭的程序没有正确释放掉记忆体,执行系统时就会觉得越来越慢,甚至不 稳定。为了解决这个问题, Android 引入了一个新的机制 -- 生命周期 (LifeCycle) 。
行程:
应用程序(一个个Activity )执行的状态称为行程(process) 。在 Android 操作系统 中 ,每个应用程序都是一个行程。 Android 系统平台 ( 准确的说是 Dalvik 虚拟机 ) 会维护一个唯一的 Activity 历史记录堆叠,并从旁观察每个应用程序行程。系统平台会依照系统的记 忆体状况,与 Activity 的使用状态,来管理记忆体的使用。Activity 类别除了负责运行程序流程,与操作界面元件之外,最重要的,就是它提供 了开发者控制行程生命周期的函式。我们已经相当习惯在 OnCreate (建立行程时的行为 ) 函数中,加入我们对这个 Activity 执行流程的控制。在前面遇到的范例中,我们并不需要对 除了 OnCreate 之外的行为做出改变。不过理解行程的生命周期,将为我们继续深入 Androi d开发打下基础。
为什麽要了解生命周期?
Android 应用程序的生命周期是由 Android 框架进行管理,而不是由应用程序直接控
制。通常,每一个应用程序(入口一般会是一个 Activity 的 onCreate 方法),都会占据一个行程 (Process) 。当系统记忆体即将不足的时候,会依照优先级自动进行行程 (process )的回收。不管是使用者或开发者,都无法确定的应用程序何时会被回收。一个 Activity 类别除了 OnCreate 函数之外,还预先定义了 OnPause( 暂停行程时的 行为 ) 、 OnResume( 继续行程时的行为 ) 等等的基本行为,当从一个 Activity 切换到另一个Activity 的时候,原本的 Activity 将经过一连串的状态改变。开发者可以在程序中添加一些各状态相对应的流程,每次 Activity 改变状态时,就会执行相对应的流程。
Activity 的状态
Android 的虚拟机 (VM) 是使用堆叠 (Stackbased) 管理。主要有四种状态:
* Active ( 活动 )
* Paused ( 暂停 )
* Stopped ( 停止 )
* Dead ( 已回收或未启动 )
Active ( 活动 )
"Active" 状态是使用者启动应用程序或 Activity 后, Activity 运行中的状态。在 Android 平台上,同一个时刻只会有一个 Activity 处于活动 (Active) 或运行(Running) 状态。其他的 Activity 都处于未启动 (Dead) 、停止 (Stopped) 、或是暂停 (Paus e)的状态。
Paused ( 暂停 )
"Paused" 状态是当 Activity 暂时暗下来,退到背景画面的状态。当我们使用 Toast 、 AlertDialog 、或是电话来了时,都会让原本运行的 Activity 退到背景画面。新出现的 Toast 、 AlertDialog 等界面元件盖住了原来的 Activity 画面。Activity 处在 "Paused" 状态时,使用者无法与原 Activity 互动。
Stopped ( 停止 )
Stopped" 状态是有其他 Activity 正在执行,而这个 Activity 已经离开萤幕,不再动作的状态。透过长按 "Home"钮,可以叫出所有处于 "Stopped"状态的应用程序列表。在"Stopped" 状态的 Activity ,还可以透过 "Notification" 来唤醒。 "Notification"会在后面章节中解说。
Dead ( 已回收或未启动 )
"Dead" 状态是 Activity 尚未被启动、已经被手动终止,或已经被系统回收的状态。要手动终止Activity ,可以在程序中呼叫"finish" 函数。如果是被系统回收,可能是因为记忆体不足了,所以系统根据记忆体不足时的回收规则,将处于 "Stopped" 状态的 Activity 所占用的记忆体回收。
我们可以写一些程序来直观查看Activity 的运作流程吗!
代码 :
public class Bmi extends Activity { private static final String TAG ="Bmi"; public void onCreate() { super.onCreate(...); Log.v(TAG,"onCreate"); } public void onStart() { super.onStart(); Log.v(TAG,"onStart"); } public void onResume() { super.onResume(); Log.v(TAG,"onResume"); } public void onPause() { super.onPause(); Log.v(TAG,"onPause"); } public void onStop() { super.onStop(); Log.v(TAG,"onStop"); } public void onRestart() { super.onRestart(); { Log.v(TAG,"onReStart"); } public void onDestroy() { super.onDestroy(); } } }
讲解
我们为 Activity 的各个状态加入了 "Log" 记录讯息。当模拟器运行时,我们可以透过"LogCat"工具来查看 Activity所处在的状态。
上面的七个状态又可以归纳成三组:
1. 资源分配 (Create/Destroy)
完整的 Activity 生命周期由 "Create" 状态开始,由 "Destroy" 状态结束。 建立(Create) 时分配资源,销毁 (Destroy) 时释放资源。
2. 可见与不可见 (Start/ReStart/Stop)
当 Activity 运行到 "Start" 状态时,就可以在萤幕上看到这个 Activity 。相反地, 当Activity 运行到 "Stop" 状态时,这个 Activity 就会从萤幕上消失。当使用者按下 Back 按钮回到上一个Activity 时,会先到 Restart 状态,再到一般的 Start 状态。
3. 使用者能否直接存取萤幕( Resume/Pause )
当有个 Toast 、 AlertDialog 、简讯、电话等讯息乱入时,原来的 Activity 会进入"Pause" 状态,暂时放弃直接存取萤幕的能力,被中断到背景去,将前景交给优先级高的事件。当这些优先级高的事件处理完后, Activity 就改进入 "Resume" 状态,此时又直接存取萤幕。
Activity 运作流程
由实际运行的记录来看,我们可以归纳出所有 Android 应用程序都遵循的动作流程:一般启动onCreate -> onStart -> onResume
启动一个 Activity 的基本流程是:分配资源给这个 Activity ( Create 状态),然 后将 Activity 内容显示到萤幕上( Start 状态)。在一切就绪后,取得萤幕的控制权( Res ume状态),使用者可以开始使用这个程序。
呼叫另一个 Activity
onPause(1) -> onCreate(2) ->onStart(2) - onResume(2) -> onStop(1)
这是个先冻结原本的Activity ,再交出直接存取萤幕能力(Pause 状态)的过程。 直到 Activity 2 完成一般启动流程后, Activity 1 才会被停止。
还原 Activity
onPause(2) -> onRestart(1) ->onStart(1) -> onResume(1) -> onStop(2) ->onDestroy(2)
点 Back 按钮可以回到原本的 Activity 。
退出结束
onPause -> onStop -> onDestroy
如果程序中有直接呼叫"finish" 函数来关闭 Activity 的话,系统假设我们很确定我们在做什麽,因此会直接跳过先冻结 (Freeze) 的阶段,暂停 (Pause) ,停止 (Stop) ,然后销毁(Destroy) 。
回收后再启动
onCreate ->onStart ->onResume
被回收掉的 Activity一旦又重新被呼叫时,会像一般启动一样再次呼叫 Activity 的onCreate 函数。
当我们使用"Android" 手机一阵子,在手机上已经执行过多个应用程序。只要按下 "Back"(返回)键, "Android" 就会开启最近一次开启过的 Activity 。这时我们要是按下多次 "Back" (返回)键,理论上迟早会返回到某个已经销毁( Destroy )的 Activity 。这时会发生什麽事呢?
如果应该开启的Activity 已经被回收了,那么这个Activity 会再次被建立( Create )出来。再次被建立出来的Activity ,当然会跟原本我们开启过的Activity 不一样啦。所以如果要让再次被建立出来的 Activity 看起来跟原本开启过的一样,那么在Activity 之间切换时,我们就要留意保留资料:最好在每次 Activity 运行到 "onPause"或 "onStop" 状态时先保存资料,然后在 "onCreate" 时将资料读出来。
参考资料
onSaveInstanceState和onRestoreInstanceState触发的时机
先看Application Fundamentals上的一段话:
Android callsonSaveInstanceState() before the activity becomes vulnerable to being destroyedby the system, but does not bother calling it when the instance is actuallybeing destroyed by a user action (such as pressing the BACK key)
从这句话可以知道,当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
通过重写一个activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我们可以清楚地知道当某个activity(假定为activity A)显示在当前task的最上层时,其onSaveInstanceState方法会在什么时候被执行,有这么几种情况:
1、当用户按下HOME键时。
这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
2、长按HOME键,选择运行其他的程序时。
3、按下电源按键(关闭屏幕显示)时。
4、从activity A中启动一个新的activity时。
5、屏幕方向切换时,例如从竖屏切换到横屏时。
在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行
总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。
至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activityA“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行
另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原