Activity 整理
lifecycle
MainActivity 打开 -> 息屏 -> 再次进入
日志:
//打开
MainActivity: onCreate:
MainActivity: onStart:
MainActivity: onResume:
//息屏
MainActivity: onPause:
MainActivity: onStop:
//再次进入
MainActivity: onRestart
MainActivity: onStart:
MainActivity: onResume:
MainActivity 打开 OtherActivity 再关闭 OtherActivity
日志:
MainActivity: onCreate:
MainActivity: onStart:
MainActivity: onResume:
//打开 OtherActivity
MainActivity: onPause:
OtherActivity: onCreate:
OtherActivity: onStart:
OtherActivity: onResume:
MainActivity: onStop:
//关闭 OtherActivity
OtherActivity: onPause:
MainActivity: onRestart:
MainActivity: onStart:
MainActivity: onResume:
OtherActivity: onStop:
OtherActivity: onDestroy:
总结:
- 在跳转时 MainActivity 会先执行 onPause,待 OtherActivity 执行到 onResume 显示出来后,执行 onStop。
- 当 OtherActivity 关闭时也会先执行 onPause, MainActivity 执行 onRestart,onStart,onResume,显示出来后,OtherActivity 执行 onStop 消失,onDestory 销毁。
暂停和继续 Activity
当 MainActivity 打开一个半透明的 Activity 时,应用会执行 onPause 进入到暂停状态,此时失去焦点。当半透明 Activity 消失时,MainActivity 执行 onResume 回到恢复状态。
如下图所示:
basic-lifecycle-paused.png暂停 Activity
当系统为您的 Activity 调用 onPause()
时,它从技术角度看意味着您的 Activity 仍然处于部分可见状态,但往往说明用户即将离开 Activity 并且它很快就要进入“停止”状态。 您通常应使用 onPause()
回调。
onPause()时,应该进行的操作:
- 检查 Activity 是否可见。如果不可见,请停止动画或其他正在进行的可能消耗 CPU 的操作。记住,从 Android 7.0 开始,暂停的应用可能会在多窗口模式下运行。 在本示例中,您可能不想停止动画或视频播放。
- 提交未保存的更改,但仅当用户离开时希望永久性保存此类更改(比如电子邮件草稿)。
- 释放系统资源,比如广播接收器、传感器手柄(比如 GPS) 或当您的 Activity 暂停且用户不需要它们时仍然可能影响电池寿命的任何其他资源。
例如,如果您的应用使用 Camera
,onPause()
方法是释放它的好位置。
@Override
public void onPause() {
super.onPause(); // Always call the superclass method first
// Release the Camera because we don't need it when paused
// and other activities might need to use it.
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
一般情况下,您不得使用 onPause()
永久性存储用户更改(比如输入表格的个人信息)。 只有在您确定用户希望自动保存这些更改的情况(比如,草拟电子邮件时)下,才能在 onPause()
中永久性存储用户更改。但您应避免在 onPause()
期间执行 CPU 密集型工作,比如向数据库写入信息,因为这会拖慢向下一 Activity 过渡的过程(您应改为在 onStop()
间执行高负载关机操作)。
您应通过相对简单的方式在 onPause()
方法中完成大量操作,这样才能加快在您的 Activity 确实停止的情况下用户向下一个目标过渡的速度。
继续 Activity
当用户从“暂停”状态继续您的 Activity 时,系统会调用 onResume()
方法。
请注意,每当您的 Activity 进入前台时系统便会调用此方法,包括它初次创建之时。 同样地,您应实现 onResume()
以初始化您在 onPause()
期间释放的组件,并执行每当 Activity 进入“继续”状态时必须进行的任何其他初始化操作(比如开始动画和初始化只在 Activity 具有用户焦点时使用的组件)。
onResume()
的以下示例对应于以上的 onPause()
示例,因此它初始化 Activity 暂停时释放的照相机。
@Override
public void onResume() {
super.onResume(); // Always call the superclass method first
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null) {
initializeCamera(); // Local method to handle camera init
}
}
保存 Activity 状态
管理 Activity 生命周期的引言部分简要提及,当 Activity 暂停或停止时,Activity 的状态会得到保留。 确实如此,因为当 Activity 暂停或停止时,Activity
对象仍保留在内存中 — 有关其成员和当前状态的所有信息仍处于活动状态。 因此,用户在 Activity 内所做的任何更改都会得到保留,这样一来,当 Activity 返回前台(当它“继续”)时,这些更改仍然存在。
不过,当系统为了恢复内存而销毁某项 Activity 时,Activity
对象也会被销毁,因此系统在继续 Activity 时根本无法让其状态保持完好,而是必须在用户返回 Activity 时重建 Activity
对象。但用户并不知道系统销毁 Activity 后又对其进行了重建,因此他们很可能认为 Activity 状态毫无变化。 在这种情况下,您可以实现另一个回调方法对有关 Activity 状态的信息进行保存,以确保有关 Activity 状态的重要信息得到保留:onSaveInstanceState()
。
系统会先调用 onSaveInstanceState()
,然后再使 Activity 变得易于销毁。系统会向该方法传递一个 Bundle
,您可以在其中使用 putString()
和 putInt()
等方法以名称-值对形式保存有关 Activity 状态的信息。然后,如果系统终止您的应用进程,并且用户返回您的 Activity,则系统会重建该 Activity,并将 Bundle
同时传递给 onCreate()
和 onRestoreInstanceState()
。您可以使用上述任一方法从 Bundle
提取您保存的状态并恢复该 Activity 状态。如果没有状态信息需要恢复,则传递给您的 Bundle
是空值(如果是首次创建该 Activity,就会出现这种情况)。
[站外图片上传中...(image-75efc2-1523588009766)]
图 2. 在两种情况下,Activity 重获用户焦点时可保持状态完好:系统在销毁 Activity 后重建 Activity,Activity 必须恢复之前保存的状态;系统停止 Activity 后继续执行 Activity,并且 Activity 状态保持完好。
注:无法保证系统会在销毁您的 Activity 前调用
onSaveInstanceState()
,因为存在不需要保存状态的情况(例如用户使用“返回”按钮离开您的 Activity 时,因为用户的行为是在显式关闭 Activity)。 如果系统调用onSaveInstanceState()
,它会在调用onStop()
之前,并且可能会在调用onPause()
之前进行调用。
不过,即使您什么都不做,也不实现 onSaveInstanceState()
,Activity
类的 onSaveInstanceState()
默认实现也会恢复部分 Activity 状态。具体地讲,默认实现会为布局中的每个 View
调用相应的 onSaveInstanceState()
方法,让每个视图都能提供有关自身的应保存信息。Android 框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复对 UI 所做的任何可见更改。例如,EditText
小部件保存用户输入的任何文本,CheckBox
小部件保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小部件提供一个唯一的 ID(通过 android:id
属性)。如果小部件没有 ID,则系统无法保存其状态。
注:由于无法保证系统会调用
onSaveInstanceState()
,因此您只应利用它来记录 Activity 的瞬态(UI 的状态)— 切勿使用它来存储持久性数据,而应使用onPause()
在用户离开 Activity 后存储持久性数据(例如应保存到数据库的数据)。
您只需旋转设备,让屏幕方向发生变化,就能有效地测试您的应用的状态恢复能力。 当屏幕方向变化时,系统会销毁并重建 Activity,以便应用可供新屏幕配置使用的备用资源。 单凭这一理由,您的 Activity 在重建时能否完全恢复其状态就显得非常重要,因为用户在使用应用时经常需要旋转屏幕。
处理配置变更
有些设备配置可能会在运行时发生变化(例如屏幕方向、键盘可用性及语言)。 发生此类变化时,Android 会重建运行中的 Activity(系统调用onDestroy()
,然后立即调用 onCreate()
)。此行为旨在通过利用您提供的备用资源(例如适用于不同屏幕方向和屏幕尺寸的不同布局)自动重新加载您的应用来帮助它适应新配置。
如果您对 Activity 进行了适当设计,让它能够按以上所述处理屏幕方向变化带来的重启并恢复 Activity 状态,那么在遭遇 Activity 生命周期中的其他意外事件时,您的应用将具有更强的适应性。
正如上文所述,处理此类重启的最佳方法是利用onSaveInstanceState()
和 onRestoreInstanceState()
(或 onCreate()
)保存并恢复 Activity 的状态。
如需了解有关运行时发生的配置变更以及应对方法的详细信息,请阅读处理运行时变更指南。
协调 Activity
当一个 Activity 启动另一个 Activity 时,它们都会体验到生命周期转变。第一个 Activity 暂停并停止(但如果它在后台仍然可见,则不会停止)时,同时系统会创建另一个 Activity。 如果这些 Activity 共用保存到磁盘或其他地方的数据,必须了解的是,在创建第二个 Activity 前,第一个 Activity 不会完全停止。更确切地说,启动第二个 Activity 的过程与停止第一个 Activity 的过程存在重叠。
生命周期回调的顺序经过明确定义,当两个 Activity 位于同一进程,并且由一个 Activity 启动另一个 Activity 时,其定义尤其明确。 以下是当 Activity A 启动 Activity B 时一系列操作的发生顺序:
- Activity A 的
onPause()
方法执行。 - Activity B 的
onCreate()
、onStart()
和onResume()
方法依次执行。(Activity B 现在具有用户焦点。) - 然后,如果 Activity A 在屏幕上不再可见,则其
onStop()
方法执行。
您可以利用这种可预测的生命周期回调顺序管理从一个 Activity 到另一个 Activity 的信息转变。 例如,如果您必须在第一个 Activity 停止时向数据库写入数据,以便下一个 Activity 能够读取该数据,则应在 onPause()
而不是 onStop()
执行期间向数据库写入数据。
Manifest 属性
语法:
<activity android:allowEmbedded=["true" | "false"]
android:allowTaskReparenting=["true" | "false"]
android:alwaysRetainTaskState=["true" | "false"]
android:autoRemoveFromRecents=["true" | "false"]
android:banner="drawable resource"
android:clearTaskOnLaunch=["true" | "false"]
android:configChanges=["mcc", "mnc", "locale",
"touchscreen", "keyboard", "keyboardHidden",
"navigation", "screenLayout", "fontScale",
"uiMode", "orientation", "screenSize",
"smallestScreenSize"]
android:documentLaunchMode=["intoExisting" | "always" |
"none" | "never"]
android:enabled=["true" | "false"]
android:excludeFromRecents=["true" | "false"]
android:exported=["true" | "false"]
android:finishOnTaskLaunch=["true" | "false"]
android:hardwareAccelerated=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:launchMode=["standard" | "singleTop" |
"singleTask" | "singleInstance"]
android:maxRecents="integer"
android:multiprocess=["true" | "false"]
android:name="string"
android:noHistory=["true" | "false"]
android:parentActivityName="string"
android:permission="string"
android:process="string"
android:relinquishTaskIdentity=["true" | "false"]
android:resizeableActivity=["true" | "false"]
android:screenOrientation=["unspecified" | "behind" |
"landscape" | "portrait" |
"reverseLandscape" | "reversePortrait" |
"sensorLandscape" | "sensorPortrait" |
"userLandscape" | "userPortrait" |
"sensor" | "fullSensor" | "nosensor" |
"user" | "fullUser" | "locked"]
android:stateNotNeeded=["true" | "false"]
android:supportsPictureInPicture=["true" | "false"]
android:taskAffinity="string"
android:theme="resource or theme"
android:uiOptions=["none" | "splitActionBarWhenNarrow"]
android:windowSoftInputMode=["stateUnspecified",
"stateUnchanged", "stateHidden",
"stateAlwaysHidden", "stateVisible",
"stateAlwaysVisible", "adjustUnspecified",
"adjustResize", "adjustPan"] >
. . .
</activity>
android:launchMode
推荐文章:
- https://blog.csdn.net/liuhe688/article/details/6754323
- https://developer.android.com/guide/topics/manifest/activity-element.html?hl=zh-cn#lmode
用例 | 启动模式 | 多个实例? | 注释 |
---|---|---|---|
大多数 Activity 的正常启动 | “standard ” |
是 | 默认值。系统始终会在目标任务中创建新的 Activity 实例并向其传送 Intent。 |
“singleTop ” |
有条件 | 如果目标任务的顶部已存在一个 Activity 实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建新的 Activity 实例。 |
|
专用启动(不建议用作常规用途) | “singleTask ” |
否 | 系统在新任务的根位置创建 Activity 并向其传送 Intent。 不过,如果已存在一个 Activity 实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建新的 Activity 实例。 |
“singleInstance ” |
否 | 与“singleTask" ”相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。 该 Activity 始终是其任务唯一仅有的成员。 |