Activity任务栈及启动模式

Activity任务栈

在android中 , 应用内的Activity是被任务栈Task来统一管理 的,默认情况下,任务栈是遵循后进先出的原则.当应用启动的时候,系统就会创建一个Task,当我们点击Home键时,当前所有的Activity就停止了,所在的Task也就成了后台任务栈,当所有的Activity都退出的时候,任务栈就清空了.当然我们可以通过设置一些属性来改变这种规则。

Activity的四种启动模式

Activity的启动模式主要是在AndroidManifest.xml文件中进行指定,或者通过Intent 的Flag属性进行指定.

ps: Activity Attribute

<activity android:name="ActivityMain" android:launchMode="singleTask"/>

Activity的四种启动模式:

  • standard
    • 每次激活Activity时都会创建Activity,并放入任务栈中,这是系统默认的启动模式.
      例如: 栈中顺序是A B C D ,此时D通过Intent跳转到A,那么栈中结构就变成 A B C D A,点击返回按钮的 显示顺序是 D C B A,依次摧毁。
  • singleTop
    • 如果在任务的栈顶正好存在该Activity的实例, 就重用该实例(调用栈顶Activity的onNewIntent()方法),否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
      例如:现在栈的情况为:A B C D,B和D的launchMode为singleTop,在D中启动Intent跳转到D,不会创建D的实例,此时栈的情况依然为:A B C D,如果通过Intent跳转到B,就会创建一个B的实例,此时的栈情况为:A B C D B
  • singleTask
    • Task栈中只能有一个对应Activity的实例,如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
      例如:现在栈的情况为:A B C D,B的launchMode为singleTask,在D通过Intent跳转到B,此时的栈情况为:A B ,CD都被弹出销毁了,通常应用于Application的首页。
  • singleInstance
    • 在一个新栈中创建该Activity实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity的实例存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例。和singleTask的主要区别是在单独的任务栈中启动,通过这个Activity再打开的其它Activity会被放入到别的任务中
      例如:Task栈1中结构为:A B C,C通过Intent跳转到了D(singleInstance),此时会存在两个任务栈,Task2 中结构为D,此时如果D通过Intent打开D,则不会创建D的实例,D跳转到C,则根据Task1中的launchMode来做不同的操作,如果C为singleTop,Task1种的栈情况依然为A B C,此时点击返回键也不会回到D

launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。

ps:Intent Flags

 Intent intent = new Intent(this, ActivityB.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
  • Intent.FLAG_ACTIVITY_NEW_TASK:在Activity中使用此flag 需要和TaskAffinity属性配合使用,在非Activity中启动activity必须要使用此flag
    例如:Task1中的任务栈:ABC,在C中启动D,如果D的Manifest指定了TaskAffinity属性,那么系统就会去寻找是否存在此TaskAffinity的任务栈,如果存在,则创建D的实例并压入栈中,如果不存在就会创建一个新的任务栈,并将此activity压入栈中,如果没有指定TaskAffinity属性,就和android:launchMode = standard效果相同。
  • Intent.FLAG_ACTIVITY_SINGLE_TOP:类似andoid:launchMode="singleTop"
  • Intent.FLAG_ACTIVITY_CLEAR_TOP:类似andoid:launchMode="singleTask",这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。通常和Intent.FLAG_ACTIVITY_NEW_TASK一同使用,用于用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。
  • Intent.FLAG_ACTIVITY_NO_HISTORY:使用这种模式启动Activity,当该Activity启动其他Activity后,该Activity就消失了,不会保留在task栈中。例如A B,在B中以这种模式启动C,C再启动D,则当前的task栈变成A B D。

清空回退栈

  • alwaysRetainTaskState
    如果 task 中根 activity 的此属性设为 “true” ,则默认的清理方式不会进行。即使过了很长时间,task 中所有的 activity 也都会保留在栈中。
  • clearTaskOnLaunch
    如果 task 中根 activity 的此属性设为 “true”,则只要用户离开并再次返回该 task,栈就会被清理至根 activity。
    如果将首页Activity的这个属性设置为true,那么只要用户离开了首页,再次返回的时候就会将其上的所有其它Activity全部清销毁。也就是每次都从首页开始。
  • finishOnTaskLaunch
    通过这个属性,当离开这个Activity所在的task,那么当用户再返回时,该Activity就会被finish掉。

TaskAffinity

affinity 表示 activity 预期所处的 task 。 缺省情况下,同一个应用中的所有 activity 都拥有同一个 affinity 值。 因此,同一个应用中的所有 activity 默认都期望位于同一个 task 中。 不过,你可以修改 activity 默认的 affinity 值。 不同应用中的 activity 可以共享同一个 affinity 值,同一个应用中的 activity 也可以赋予不同的 task affinity 值。

affinity 将在以下两种情况下发挥作用:

  • 当启动 activity 的 intent 包含了FLAG_ACTIVITY_NEW_TASK标志。见上文
  • 当一个 activity 的allowTaskReparenting属性设为 “true”。
    taskAffinity用于指定当前Activity所关联的Task,allowTaskReparenting用于配置是否允许该activity可以更换从属task,通常情况二者连在一起使用,用于实现把一个应用程序的Activity移到另一个应用程序的Task中。
    举例: 一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着Affinity的Task中。如果e-mail中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的,但是,现在它作为e-mail Task的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见,并且,当e-mail Task再次进入前台时,就看不到它了。

sigleTask特殊之处

  1. 设置了”singleTask”启动模式的Activity,如果设置了taskAffinity属性值,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的任务存在;如果存在这样的任务,它就会在这个任务中启动,否则就会在新任务中启动。

  2. 如果没有设置taskAffinity属性值,它会在已有的任务中查看是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity实例会位于任务的堆栈顶端中。

参考[Android Heroes Reading Notes 4]

你可能感兴趣的:(android,管理,栈,应用)