Android 之 Tasks and Back Stack

512 查看


默认行为
1. 当Activity A启动Activity B, A stopped, 系统保存A状态。当Back pressed, 则A resumed 并恢复相关状态。
2. 当Home button pressed, 则当前activity stopped, task 进如background,系统保存每个task的状态。当用户启动了之前开始task的app,则此task进入前台,并且恢复task栈顶的Activity。
3. 当用户点击Back, 则当前Activity会被弹出task stack 并且被destroy,系统也不再retain其状态。
4. Activities可被实例化多次,甚至时从其他tasks。

Saving Activity State

当Activity stopped, 系统会默认保存其状态。当也还是建议使用回调函数保存Activity的状态,以防止系统在内存不存进行内存回收,销毁掉进入后台的task。这种情况下,当系统再次进入该task时,系统仍然具有task链,但是在将task栈顶的Activity进行显示时,将会是重新create,而不是resume。所以应主动使用回调函数 onSaveInstanceState() 来保存Activity State。

Managing Tasks

Principal < activity > attributs

taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch

Principal intent flags:

FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP

Define launch modes

  1. 使用Manifest指定, task
  2. 使用Intent Flags

当用A启动B时,A指定了启动B的Flag,而B也在Manifest中指定了不同task。此种情况下,在Intent中的指定Flags将覆盖掉Manifest指定的task。

此外,有些launchmode 在flag中有,但在Manifest中没有,同样,在Manifest中有,flag中有。

  • 使用Manifest File

指定activity的launchMode属性:

|standard|singleTop|singleTask|singleInstance|
|---   |   |   |   |
|默认的,可被实例化多次,可分属不同task,也可在同一task| 当要启动的Activity 存在栈顶,在该模式下,系统将把启动该Activity的Intent通过调用onNewIntent()方法将路由至栈顶的Activity实例,不再启动的新的实例。如果要启动的Activity的实例不再栈顶,则启动新的实例。注意:该种模式下,back button无法返回调用onNewIntent之前的状态,因为task back stack还是保持原样。|创建新的task,实例化Activity到task的栈底。但若时此时现有task stack中已经有该Activity的实例,那么系统就不会启动新的task和实例,而是路由到该task中的Activity,并销毁task stack中在这之上的Activity,使之成为栈顶,然后将该Intent通过onNewIntent路由到Activity。 同一时刻,Activity只有一个实例。|类似于singleTask,Activity只有一个实例,并且也会时task的为一个栈元素,它启动的任何Activity都将会出现在其他的task栈中。

Android Browser就是一个使用singleTask模式的应用。
此外,对于back stack,不论Activity时被启动到一个新的task还是在启动它的Activity所在task stack,back button都可以返回到上一个Activity。
另外,对于启动使用singleTask模式的Activity,那么系统首先按照它本身模式启动,之后会将该Activity所在的task stack整体迁移到启动它的back stack。如图所示:

  • 使用Intent Flags

在startActivity可指定的flag包括:

FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_SINGLE_TOP FLAG_ACTIVITY_CLEAR_TOP
与singTask属性相同 与singleTop相同 如果要启动的Activity已经存在task栈中,那么系统将会clear掉在Activity元素到task 栈顶的所有Activity,然后将Intent通过onNewIntent()传递给已经在栈顶的Activity。该flag通常和FLAG_ACTIVITY_NEW_TASK一起使用。

Handling affinities

affinity 属性暗示了Activity更倾向加入的task。默认,同一个Application里的Activity更倾向于在同一个task里。可通过修改activity元素的taskAffinity属性。该属性的值时一个字符串,默认的为包名,因此,如果希望倾向于启动在不同的task,那么指定以个不同于包名的字符串即可。

使用Affinity的两种情况
- 使用FLAG_ACTIVITY_NEW_TASK

当A启动B时,若指定了FLAG_ACTIVITY_NEW_TASK,那么系统首先寻找倾向的task来装载这个新的B。如果存在与B具有相同Affinity的task,则将其启动到该task,否则启动新的task。比如InCallScreen,当用户按Home离开该Activity,该如何回到该Activity,除了在launch里启动之外(如果launchMode为main的话),还可以在notification bar中显示。
- activity元素的属性allowTaskReparenting 为true,
意思就是本Appliancation中的Activity A 具有其他Application里的Activity B相同的affinity。那么在A中启动B时,B将隶属于A的task,那么在B所属的Application启动后,B将从A所属的task中通过Reparenting到B所属的Application应用。

Clearing the back stack

若用户离开task 很长时间,系统将会清理task,只留下task stack的root activti。当用户重返task,只会restore root Activtiy。但几个Activity可以修改这样的行为

  • alwaysRetainTaskState
    若该属性被设置到root activity of a task,那么默认行为就不会发生。
  • clearTaskOnLaunch
    若root activity of a task的该属性设为true,不论用户离开还是重新进入task, 都会清掉除了root activity之外的activities。 与alwaysRetainTaskState刚好相反。
  • finishOnTaskLaunch
    仅作用于单个Activity,不保存状态,离开即销毁。若其在一个task中,当离开后,该activity即被销毁,将其从task stack栈中弹出,在进入该task时,将会是该task的上一个activity在前台。也可作用于root activity of task。 比如InCallScreen用完后,即可销毁。