Earth Guardian

You are not LATE!You are not EARLY!

0%

四大组件 -- Activity

基本概念

Activity 用来做界面显示,交互,也是程序的入口。

生命周期

生命周期流转图

0018_activity_lifecycle.png

注意: 在实现生命周期方法时必须始终先调用超类实现,然后再执行其他操作。

1
2
3
4
5
6
@Override
protected void onResume() {
super.onResume();
...
// my code.
}

生命周期回调方法汇总表

  • 生命周期回调方法汇总表

0018_lifecycle.png

  • onPauseonStop 的区别
    onPause:失去焦点,不可交互
    onStop:完全被遮挡,Activity 不可见

示例Activity 在弹出继承自 ActivityDialog 时,只是失去焦点,并没有完全不可见,所以只会执行 onPause ;而 Activity 在启动另一个 Activity 时被完全遮挡,就会执行到 onStop
常见错误: 普通 Dialog 弹出并不影响 Activity 声明周期。生命周期只有 Activity 相互遮挡才会出现变化。

A 启动 B 生命周期的执行顺序

1
2
3
4
5
6
7
8
// 启动A
A:: onCreate -> A:: onStart -> A:: onResume
// 点击A中的button启动B
A:: onPause -> B:: onCreate -> B:: onStart -> B:: onResume -> A:: onStop
// 在B中点击Back退出
B:: onPause -> A:: onRestart -> A:: onStart -> A:: onResume -> B:: onStop -> B:: onDestroy
// 在A中点击Back退出
A:: onPause -> A:: onStop -> A:: onDestroy

可以清楚的看到在 A 启动 B 的流程中,onPause 在失去焦点后就立即执行,当 B 完全启动后并遮挡了 AonStop 才开始执行。同理,B 在退出过程中,等 A 完全恢复并遮挡 B 后,B 才开始执行 onStop -> onDestroy
onStop -> onRestart 这个流程出现在:Activity 被遮挡但没有销毁,下次恢复时就会执行 onRestart -> onStart

finish() 对生命周期的影响

  • onCreate 中调用,执行顺序 onCreate -> onDestroy
  • onStart 中调用,执行顺序 onCreate -> onStart -> onStop -> onDestroy

Activity 重建的影响因素

如下因素的变化,都会导致 Activity 重建,也就是会走 onDestroy -> onCreate

  • mcc
    国际移动用户识别码所属国家代号是改变了,sim 被侦测到了,去更新 mccmcc 是移动用户所属国家代号
  • mnc
    MNC 是移动网号码,最多由两位数字组成,用于识别移动用户所归属的移动通信网
  • locale
    地址改变了,用户选择了一个新的语言会显示出来
  • touchscreen
    触摸屏是改变了,通常是不会发生的
  • keyboard
    键盘发生了改变,例如用户用了外部的键盘
  • keyboardHidden
    键盘的可用性发生了改变
  • navigation
    导航发生了变化,通常也不会发生
  • screenLayout
    屏幕的显示发生了变化,不同的显示被激活
  • fontScale
    字体比例发生了变化,选择了不同的全局字体
  • uiMode
    用户的模式发生了变化
  • orientation
    屏幕方向改变了
  • screenSize
    屏幕大小改变了
  • smallestScreenSize
    屏幕的物理大小改变了,如:连接到一个外部的屏幕上

这些影响因素可以在 AndroidManifest.xml 中设置来屏蔽掉,凡是在这申明后,将不会影响生命周期。

1
2
<activity android:name=".fourcomponents.ActivityLifeCycleA"
android:configChanges="***">

屏幕旋转对生命周期的影响

  • 常规流程 Activity 销毁重建
    屏幕旋转会完整的触发这两个生命周期,其中状态恢复在 onCreateonRestoreInstanceState 中都可以实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TAG:: onCreate
TAG:: onStart
TAG:: onResume
// 开始旋转屏幕,Activity被销毁
TAG:: onPause
// 触发状态保存
TAG:: onSaveInstanceState, outState.value = hello InstanceState
TAG:: onStop
TAG:: onDestroy
// Activity重建
TAG:: onCreate
// 状态恢复,可以在onCreate中恢复
TAG:: onCreate, savedInstanceState.value = hello InstanceState
TAG:: onStart
// 触发状态回复,也可以在这里恢复
TAG:: onRestoreInstanceState
TAG:: onRestoreInstanceState, savedInstanceState.value = hello InstanceState
TAG:: onResume
// 界面显示
  • 避免 Activity 销毁重建
    在屏幕旋转时,避免 Activity 销毁重建,可以在 AndroidManifest.xml 中设置对应属性(Android 3.2 及以上需要设置 screenSize):
1
2
<activity android:name=".fourcomponents.ActivityLifeCycleA"
android:configChanges="orientation|screenSize">

设置后屏幕旋转将完全不影响 Activity 的生命周期,如果想监听屏幕旋转,可以重写如下方法:

1
2
3
4
5
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(TAG, "onConfigurationChanged: newConfig = " + newConfig);
}

“锁屏/解锁”对生命周期的影响

“锁屏/解锁” 整个流程包含:锁屏,亮屏,解锁三个步骤:

不涉及横竖屏切换

如:当前 Activity 为竖屏,在竖屏状态下,锁屏并解锁,不做方向切换,即正常流程:
锁屏:onPause -> onStop
解锁:onRestart -> onStart -> onResume

涉及横竖屏切换

如:当前 Activity 为横屏,在横屏状态下锁屏会显示锁屏界面,涉及方向切换,当前 Activity 会被销毁重建。
锁屏:onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume -> onPause

  • 解锁后当前 Activity 变为竖屏
    解锁:onResume
  • 解锁后当前 Activity 仍然转换为横屏
    即会出现当前 Activity 销毁重建过程
    解锁:onResume -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume

横竖屏切换监听屏幕旋转

如:当前 Activity 为横屏,并且设置了属性 android:configChanges="orientation|screenSize" 。即当前 Activity 不会销毁重建,方向切换时会被监听。
锁屏:onPause -> onStop -> onConfigurationChanged,此时当前 Activity 已经被切换到竖屏。
解锁:onRestart -> onStart -> onResume -> onConfigurationChanged

小结

  • 屏幕旋转
    如果涉及屏幕旋转,当前 Activity 在“锁屏/解锁”两个阶段都会出现销毁重建(onDestroy -> onCreate),如果此时监听了屏幕旋转,则在方向切换时仅执行 onConfigurationChanged
  • 锁屏
    总体来说会先执行 onPause -> onStop,即不可见流程。如果屏幕旋转当前 Activity 重建,会执行到 onPause,同时解锁会直接从 onResume 开始;如果监听了旋转,则屏幕切换时仅会执行 onConfigurationChanged
  • 亮屏
    不影响生命周期
  • 解锁
    总体来说会先执行 onRestart --> onResume,即恢复可见流程。如果当前 Activity 重建过,则直接从 onResume 恢复;如果监听了旋转,则屏幕切换时仅会执行 onConfigurationChanged

?为什么锁屏时,如果出现 Activity 销毁重建时,只执行到 onPause,而不执行 onStop ?

Home 键对生命周期的影响

按下 Home不影响生命周期,正常的不可见和恢复可见流程:
不可见流程:onPause -> onStop
恢复可见流程:onRestart -> onStart -> onResume

状态栏下拉对生命周期的影响

下拉状态栏不影响生命周期,但是如果需要监听状态栏下拉,可以重写如下方法:

1
2
3
4
5
6
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// 状态栏弹出和收回,都会触发这次事件
Log.d(TAG, "onWindowFocusChanged: ");
}

保存 Activity 的状态

状态保存和恢复
0018_restore_instance.png

涉及到两个函数:onSaveInstanceState()onRestoreInstanceState() ,这两个函数大部分情况下并不会成对出现。
如果没有重写这两个函数,系统 Activity 类的 onSaveInstanceState() 默认实现也会恢复部分 Activity 状态。具体地讲,默认实现会为布局中的每个 View 调用相应的 onSaveInstanceState() 方法,让每个视图都能提供有关自身的应保存信息。Android框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复对 UI 所做的任何可见更改。例如 EditText 小部件保存用户输入的任何文本,CheckBox 小部件保存复选框的选中或未选中状态。

注意:想要保存其状态的每个小部件,必须提供一个唯一的 ID(通过 android:id 属性)。如果小部件没有 ID,则系统无法保存其状态;如果是相同的 ID,数据会被覆盖,在恢复时数据显示出错。

保存的数据

数据通过 Bundle 保存起来,使用 putString()putInt() 等方法以[名称-值]对形式保存有关 Activity 状态的瞬时数据,如成员变量,UI 状态等。如果需要保存持久数据,需要在 onPause 中保存。

onSaveInstanceState()触发时机

Activity 不可见时触发,也就是 onPause --> onSaveInstanceState --> onStop,但是系统并不是每次都会调用。

调用

遵循一个重要原则,即当系统存在“未经你许可”销毁 Activity 的可能时,onSaveInstanceState 会被系统调用,这是系统的责任:必须要提供一个机会让你保存你的数据。

  • 启动另外一个 Activity 并被遮挡
  • 屏幕旋转时当前 Activity 销毁并被重新创建
  • Home 键相关操作
  • 按下电源键灭屏

不调用

  • 直接退出当前 Activity
  • kill 命令杀掉

onRestoreInstanceState()触发时机

Activity 恢复可见时触发,也就是 onStart --> onRestoreInstanceState --> onResume,同样系统也不是每次都会调用。

调用

重要原则,即当 Activity 确实已经被销毁。

  • 屏幕旋转时当前 Activity 销毁并被重新创建

不调用

  • Activity 并没有销毁而只是进入生命周期恢复过程中,并不会被调用,直接走流程 onRestart --> onStart --> onResume
  • kill 命令杀掉

示例

可以参考:“屏幕旋转对生命周期的影响”中“常规流程 Activity 销毁重建”的 log 打印。

Activity存储方式:栈

基本概念

  • 返回栈(Back Stack)
    返回栈: 这些 Activity 按照各自的打开顺序排列在栈中,表示 Activity 的存储方式。返回栈以“后进先出”对象结构运行,并且栈中的 Activity 永远不会重新排列,仅推入和弹出栈。由当前 Activity 启动时推入堆栈;用户使用“返回”按钮退出时弹出堆栈。

0018_Activity_stack_diagram_backstack.png

源码中查看推测是如下结构来存储返回栈的,但是似乎不像是栈的操作?

1
2
3
// TaskRecord.java中定义,暂时没有看出来是栈存储结构?
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities;
  • 任务(Task)
    任务:在执行特定作业时与用户交互的一系列 Activity,使用返回栈记录这些 Activity 的执行顺序。任务分为前台任务和后台任务,前台任务接受用户交互;任务被移动到后台时,整个返回栈顺序不变。任务可以是同一个应用程序中的 Activity,也可以是跨应用的 Activity,放到同一个任务中,以维护这种无缝的用户体验。

0018_diagram_multitasking.png

源码中通过如下方式来记录前后台任务列表,每个任务对应一个 TaskRecord

1
2
3
4
5
6
// ActivityStatck.java
/**
* The back history of all previous (and possibly still
* running) activities. It contains #TaskRecord objects.
*/
private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();

前后台任务切换时,仅仅把需要的后台任务移动到最前面,其他任务顺序不变:

1
2
3
4
5
// ActivityStatck::moveTaskToFrontLocked方法中
...
// Shift all activities with this task up to the top
// of the stack, keeping them in the same internal order.
insertTaskAtTop(tr, null);

示例

  • 命令
    adb shell dumpsys activity,通过该命令可以显示所有 Activity 的任务及存储信息,对应源码为:
1
2
3
4
5
6
7
8
9
10
// 1. ActivityManagerService.java
void dumpActivitiesLocked(***)
// 2. ActivityStackSupervisior.java
boolean dumpActivitiesLocked(***)
// 3. TaskRecord.java
public String toString()
// 4. ActivityRecord.java
public String toString()
// 5. ProcessRecord.java
public String toString()
  • 任务只包含同一个应用的 Activity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Display #0 (activities from top to bottom):
Task id #482
TaskRecord{5c00e23 #482 A=com.ymzs.androidbasicknowledge U=0 sz=5}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.androidbasicknowledge/.MainActivity }
Hist #4: ActivityRecord{18068e4d u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA t482}
Hist #3: ActivityRecord{3048f0d9 u0
// 在ActivityLifeCycleB中再次启动ActivityLifeCycleA
com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleB t482}
Hist #2: ActivityRecord{214418e1 u0
// 在ActivityLifeCycleA中启动ActivityLifeCycleB
com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleB t482}
Hist #1: ActivityRecord{1e375a73 u0
// 启动ActivityLifeCycleA
com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA t482}
Hist #0: ActivityRecord{19cecd32 u0
// 启动MainActivity
com.ymzs.androidbasicknowledge/.MainActivity t482}

由于返回栈中的 Activity 永远不会重新排列,因此如果应用启动特定 Activity,则会创建该 Activity 的新实例并推入堆栈中(而不是将 Activity 的任一先前实例置于顶部),因此应用中的一个 Activity 可能会多次实例化。如上面 Log 显示,AB 有多次实例化。

0018_diagram_multiple_instances.png

  • 任务包含不同应用的 Activity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1. ActivityManagerService::dumpActivitiesLocked打印
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
// 2. ActivityStackSupervisior::dumpActivitiesLocked打印
Display #0 (activities from top to bottom):
Stack #1:
Task id #478
// 3. TaskRecord::toString打印,其中A表示affinity的值,sz表示size
TaskRecord{f8000a3 #478 A=com.ymzs.mytensorflowandroid U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.mytensorflowandroid/.MainActivity }
// MainActivity中启动图库应用com.android.gallery3d/.app.Gallery
// 4. ActivityRecord::toString打印,t表示task_id
Hist #1: ActivityRecord{1ce46759 u0 com.android.gallery3d/.app.Gallery t478}
Intent { act=android.intent.action.PICK dat=content://media/external/images/media cmp=com.android.gallery3d/.app.Gallery }
// 5. ProcessRecord::toString打印,13594表示进程id,u0a10表示userid
ProcessRecord{24a57d18 13594:com.android.gallery3d/u0a10}
// 程序入口,启动MainActivity
Hist #0: ActivityRecord{1a87e335 u0 com.ymzs.mytensorflowandroid/.MainActivity t478}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.mytensorflowandroid/.MainActivity bnds=[276,999][540,1292] }
ProcessRecord{3ac41fa0 13096:com.ymzs.mytensorflowandroid/u0a155}

使用清单文件定义启动模式

在清单文件中声明 Activity 时,可以使用 android:launchMode 属性指定 Activity 应该如何与任务关联,默认为 android:launchMode="standard"launchMode 属性的启动模式共有四种:

standard

系统默认,Activity 会被多次实例化。

singleTop

如果当前任务的顶部已存在该 Activity 的一个实例,则系统不会创建 Activity 的新实例;如果不在顶部,则和 standard 一样,创建多个实例。假设任务的返回栈顺序是 A-B-C-D,并且 D 位于顶部,再启动 D 时,示例对比:

  • 如果 Dstandard 模式,将会新建D的实例,返回栈为 A-B-C-D-D
  • 如果 DsingleTop 模式,不会创建D的实例,返回栈还是 A-B-C-D

singleTask

系统根据 taskAffinity 来决定是否开启新任务,taskAffinity 如果不设置,默认值为包名。已有的任务中如果已经存在该 Activity 实例,下次调用时会把该任务的返回栈中位于这个实例上面所有的 Activity 全部结束掉,即最终这个 Activity 实例会位于该任务的堆栈顶端中。

  • taskAffinity 为默认值或包名,在原任务中装载该 Activity。如下示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 任务及返回栈信息
// MainActivity --> A --> B
Task id #507
TaskRecord{24103cd5 #507 A=com.ymzs.androidbasicknowledge U=0 sz=3}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.androidbasicknowledge/.MainActivity }
Hist #2: ActivityRecord{3cae8310 u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleB t507}
Hist #1: ActivityRecord{227bef6a u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA t507}
Hist #0: ActivityRecord{db2c04f u0 com.ymzs.androidbasicknowledge/.MainActivity t507}

// MainActivity --> A --> B --> A,即B中重新启动A
// B被结束掉,并执行onDestroy销毁,A重新回到返回栈栈顶
Task id #507
TaskRecord{24103cd5 #507 A=com.ymzs.androidbasicknowledge U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.androidbasicknowledge/.MainActivity }
Hist #1: ActivityRecord{227bef6a u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA t507}
Hist #0: ActivityRecord{db2c04f u0 com.ymzs.androidbasicknowledge/.MainActivity t507}

对应的生命周期流程:
B:: onPause -> A:: onNewIntent -> A:: onRestart -> A:: onStart -> A:: onResume -> B:: onStop -> B:: onDestroy

  • taskAffinity 不是包名,开启新的任务并加载该 Activity 到底部,后续新开启的 Activity 也会在这个新任务中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 启动流程仍然是MainActivity --> A --> B
Stack #1:
// 开启A,A的affinity名称为com.ymzs.androidbasicknowledge.singleTask,后续开启的B也在这个任务中
// 如果B再调用A,则B被返回栈弹出销毁,使A到栈顶显示
Task id #509
TaskRecord{1fb922e2 #509 A=com.ymzs.androidbasicknowledge.singleTask U=0 sz=2}
Intent { flg=0x10000000 cmp=com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA }
Hist #1: ActivityRecord{3b4246dc u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleB t509}
Hist #0: ActivityRecord{3cd3c703 u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA t509}

// 程序入口进入MainActivity, affinity名称为包名com.ymzs.androidbasicknowledge
Task id #508
TaskRecord{740e673 #508 A=com.ymzs.androidbasicknowledge U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.androidbasicknowledge/.MainActivity }
Hist #0: ActivityRecord{98712e4 u0 com.ymzs.androidbasicknowledge/.MainActivity t508}

singleInstance

系统会启动一个新的任务来装载该 Activity,并且该 Activity 始终是其任务唯一仅有的成员,也就是 Activity 和任务是一一对应的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 启动顺序 MainActivity --> ActivityLifeCycleA --> ActivityLifeCycleB
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #1:
// MainActivity和ActivityLifeCycleB属于同一应用程序,默认放到同一个任务中
Task id #489
TaskRecord{8812eba #489 A=com.ymzs.androidbasicknowledge U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.androidbasicknowledge/.MainActivity }
Hist #1: ActivityRecord{2408fb5a u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleB t489}
Intent { flg=0x10400000 cmp=com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleB }
ProcessRecord{37f1bd8e 13928:com.ymzs.androidbasicknowledge/u0a156}
Hist #0: ActivityRecord{214f1aee u0 com.ymzs.androidbasicknowledge/.MainActivity t489}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.ymzs.androidbasicknowledge/.MainActivity bnds=[804,999][1068,1292] }
ProcessRecord{37f1bd8e 13928:com.ymzs.androidbasicknowledge/u0a156}

// ActivityLifeCycleA设置为"singleInstance"模式,因此该Activity单独且唯一的存在于一个任务中
Task id #490
TaskRecord{1dbdd3e5 #490 A=com.ymzs.androidbasicknowledge U=0 sz=1}
Intent { flg=0x10000000 cmp=com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA }
Hist #0: ActivityRecord{4b095d9 u0 com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA t490}
Intent { flg=0x10000000 cmp=com.ymzs.androidbasicknowledge/.fourcomponents.ActivityLifeCycleA }
ProcessRecord{37f1bd8

注意:
进入顺序为 MainActivity --> ActivityLifeCycleA --> ActivityLifeCycleB
但是退出顺序为 ActivityLifeCycleB --> MainActivity --> ActivityLifeCycleA

Log 中可以看出,MainActivityActivityLifeCycleB 是在同一个任务中的返回栈中,所以按返回键会先退出 ActivityLifeCycleB,然后按照栈的顺序进入 MainActivity,再次按返回键退出 MainActivity 后,前台任务完全退出,进入 ActivityLifeCycleA 所在的任务。

总结

  • 实例数,standard 标准模式会开启多个实例,singleTop 有条件单个实例,singleTasksingleInstance 都是单个实例(单例模式)。
  • taskAffinity 决定了 singleTask 是否开启新的任务

启动模式引入新的方法 onNewIntent

定义

protected void onNewIntent(Intent intent) {}
如果 Activity 已经实例化但需要重新加载时,会先执行 onNewIntent,然后再执行生命周期函数。

示例

  • singleTop 中,如果 B 已经在栈顶,执行顺序 B:: onPause --> B:: onNewIntent --> B:: onResume
  • singleTasksingleInstance 中,如果 A 已经存在于任务中,则再次启动 A 时,执行顺序 A:: onNewIntent --> A:: onRestart --> A:: onStart --> A:: onResume

注意事项

重写 onNewIntent,必须调用 setIntent 来更新 intent,否则默认 getIntent 还是拿到之前的 intent。参考源码注释:

1
2
* <p>Note that {@link #getIntent} still returns the original Intent.  You
* can use {@link #setIntent} to update it to this new Intent.

使用 Intent 标志定义启动模式

启动 Activity 时,可以通过在传递给 startActivity()Intent 中加入相应的标志,修改 Activity 与其任务的默认关联方式。

注意:Intent 中设置的标志优先级高于 Activity 在清单文件中的定义

可用于修改默认行为的标志包括:

  • FLAG_ACTIVITY_NEW_TASK
    如果 taskAffinity 的任务存在,则不用新开任务,不管该 Activity 是否存在都会创建新实例。如果不存在则新开任务,比如在 BroadcastReceiver 中开启 Activity 就需要使用该标志
  • FLAG_ACTIVITY_SINGLE_TOP
    singleTop 启动模式有相同的行为
  • FLAG_ACTIVITY_CLEAR_TOP
    如果 Activity 已在当前任务中运行,则会销毁当前任务返回栈中顶部的所有 Activity,直到该 Activity 位于栈顶

注意事项

  • 屏幕旋转,需要有平滑的用户体验
  • 用户数据在 Activity 跳转时不能丢失
  • 特定场景下进程可能会被杀掉·