|
生命周期作者在初级章节中一直努力地传达给读者:编写 Android 平台的基本应用程式, 跟编写桌面应用程式的难度,两者并没什麽不同。甚至因为 Android 平台拥有 免费、跨平台的开发工具,使得 Android 平台应用程式的开发更为单纯。
但是请别忘了,Android 平台也是个手机作业系统。撇掉其他功能不谈,手机的 特性,就是应该能随时在未完成目前动作的时候,离开正在使用的功能,切换到 接电话、接收简讯模式...而且在接完电话回来应用程式时,还希望能看到一样 的内容。
现在使用者使用智慧型手机,大多已习惯使用多工(Multi-Task)的作业系统(如 Windows Mobile),可以在用手机听音乐的同时,也执行其他多个程式。同时执 行多个程式有它的明显好处,但是也有它的严重的缺点。每多执行一个应用程式, 就会多耗费一些系统记忆体。而手机里的记忆体是相当有限的。当同时执行的程 式过多,或是关闭的程式没有正确释放掉记忆体,执行系统时就会觉得越来越慢, 甚至不稳定。
为了解决这个问题, Android 引入了一个新的机制 — 生命周期 (Life Cycle)。
行程应用程式(一个个 Activity)执行的状态称为行程(process)。在 Android 作 业系统中,每个应用程式都是一个行程。Android 系统平台(准确的说是 Dalvik 虚拟机)会维护一个唯一的 Activity 历史记录堆叠,并从旁观察每个应用程式 行程。系统平台会依照系统的记忆体状况,与 Activity 的使用状态,来管理记 忆体的使用。
Activity 类别除了负责运行程式流程,与操作介面元件之外,最重要的,就是 它提供了开发者控制行程生命周期的函式。我们已经相当习惯在 OnCreate (建 立行程时的行为)函式中,加入我们对这个 Activity 执行流程的控制。在前面 遇到的范例中,我们并不需要对除了 OnCreate 之外的行为做出改变。不过理解 行程的生命周期,将为我们继续深入 Android 开发打下基础。
为什麽要了解生命周期Android 应用程式的生命周期是由 Android 框架进行管理,而不是由应用程式 直接控制。
通常,每一个应用程式(入口一般会是一个 Activity 的 onCreate 方法),都 会占据一个行程(Process)。当系统记忆体即将不足的时候,会依照优先级自动 进行行程(process)的回收。不管是使用者或开发者,都无法确定的应用程式何 时会被回收。
一个 Activity 类别除了 OnCreate 函式之外,还预先定义了 OnPause(暂停行 程时的行为)、OnResume(继续行程时的行为)等等的基本行为,当从一个 Activity 切换到另一个 Activity 的时候,原本的 Activity 将经过一连串的 状态改变。开发者可以在程式中添加一些各状态相对应的流程,每次 Activity 改变状态时,就会执行相对应的流程。
要让使用者有好的使用经验,Activity 需要在各个周期点上负责保管状态、恢 复状态、传送资料等工作。
Activity 的状态Android 的虚拟机(VM)是使用堆叠 (Stack based) 管理。主要有四种状态:
Active (活动)Paused (暂停)Stopped (停止)Dead (已回收或未启动)Active (活动)「Active」状态是使用者启动应用程式或 Activity 後,Activity 运行中的状 态。
在 Android 平台上,同一个时刻只会有一个 Activity 处於活动(Active)或运 行(Running)状态。其他的 Activity 都处於未启动(Dead)、停止(Stopped)、或 是暂停(Pause)的状态。
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 所占用的记忆体回收。
记忆体不足时的行为记忆体不足时,Dalvik 虚拟机会根据其记忆体回收规则来回收记忆体:
先回收与其他 Activity 或 Service/Intent Receiver 无关的行程(即优先回收独立的Activity);再回收处於「Stopped」状态的其他类型 Activity(在背景等待的Activity)。最久没有使用的 Activity 优先回收(比较官方的说法是 "根据 LRU 演算法...");还不够?回收 Service 行程;快不行啦,关掉可见的 Activity/行程;关闭当前的 Activity 。
当系统缺记忆体缺到开始「4. 关掉可见的 Activity/行程」时,大概我们换机子的时机也早该到啦!
观察 Activity 运作流程讲了这麽多虚的,我们可以写一些程式来直观查看 Activity 的运作流程吗?
当然可以。在上一章记录与侦错 (Log)中,我们学到的「Log」工具,正好可以在查看 Activity 的运作流程时派上用场。
打开「src/com/demo/android/bmi/Bmi.java」,在程式中加入一些「Log」记录点:
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();
Log.v(TAG,"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 状态)。在一切就绪後,取得萤幕的控制权(Resume 状态),使用者可以开始使用这个程式。
呼叫另一个 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」时将资料读出来。
Back 按键的处理当按下 Back 按钮时,将进程杀掉,虽然这种方法比较野蛮,但也是一种办法。 流程如下所示:
onKeyBackDown -> finish() -> onDestroy -> kill process
复制代码
示例代码如下所示:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
finish ();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//Kill myself
android.os.Process.killProcess(android.os.Process.myPid());
}
复制代码
参考资料
Activity Cycle
Activity 的生命周期 |
|