任务和回退栈

来源:互联网 发布:湖南文艺出版社 知乎 编辑:程序博客网 时间:2024/05/16 18:28

任务和回退栈

  一个应用通常有多个Activity。每个Activity围绕着用户要执行的具体行为被设计,其可以启动其他的Activity。例如,邮件应用有一个Activity用来展示新消息列表。当用户点击一个消息项,打开一个新Activity来查看该条消息详情。
  一个Activity也能启动一个设备上的其他应用的Activity。例如,如果你的应用想要发一封邮件,则你可以定义一个执行”发送”行为且包含需要数据(比如邮件地址和消息体)的Intent。其他应用程序声明了处理这种的类型Intent的Activity将被打开。上面的情况,定义的Intent是要发送邮件,所以邮件应用的“撰写”Activity启动(如果有多个Activity支持这一相同的Intent,则系统会让用户选择使用哪一个)。当邮件被发送,你的Activity将恢复,这看起来好像邮件Activity是你的应用的一部分。尽管activity来自不同的应用,Android通过保持所有的Activity在一个相同的任务栈来维持无缝的用户体验。
  任务是当执行一项具体工作时用户与之交互的Activity的集合。这些Activity按打开的顺序被放置在一个栈里(回退栈)。
  设备的主屏幕是大部分任务启动的地方。当用户在桌面上点击一个应用程序图标时,这个应用程序的任务被调到前台。如果这个应用程序没有任务存在,则会创建一个新的任务,并且该应用的“主”Activity将被打开作为该任务栈的根Activity。
  当当前的Activity启动另一个Activity时,这个新的Activity被压入到任务栈的栈顶。前一个Activity仍在任务栈里,只是被标记为停止状态。当一个Actvity停止,系统保持着用户交互的当前状态。当点击返回键时,当前的Activity从任务栈的栈顶弹出(该Activity被销毁),之前的Activity恢复。Activity绝不会在任务栈中重新排列,仅会将启动的Activity压入栈中,将点击返回键后的Activity弹出栈中。下图展示了Activity在时间进程上的行为:
这里写图片描述

  如果用户持续点击返回键,则每次在栈顶的Activity会被弹出且展示之前的Activity,直到返回到主界面。当所有的Activity都从任务栈中移除,该任务不再存在。
  当用户开启一个新的任务或通过Home键回到主屏幕时,任务作为一个整体的单元被移动到后台。当处于后台,该任务栈中所有Activity被停止,但任务栈仍在,其只是简单地失去了焦点。如下图所示:
这里写图片描述

  当用户重新拉起应用,则其任务会重新回到前台。
  注意后台可以同时保持多个任务。但是,如果用户在后台同时运行着多个任务,则系统可能会销毁后台的Activity以回收内存,这会是这些Activity的状态丢失(关于更多状态保持与恢复的内容,请查看Android状态保存与恢复)。
  因为在任务栈中的Activity绝不会重新排列,所以如果应用运行用户启动一种具体的Activity多余一个,则这种Activity的新的实例将被创建并压入任务栈中,而不是将之前的该Activity的实例移到栈顶。像这样,你的应用中的一个Activity可能会被实例化多次,甚至是在不同的任务栈中。如下图所示:
这里写图片描述

  然而,如果你不想一个Activity被实例化多次,则可以修改这种行为。这将在后面的“管理任务栈”一节讲到。
  下面总结一下Activity和任务的默认行为:

  • 当Activity A启动Activity B,Activity A停止,但系统仍会保持它的状态。如果用户在Activity B点击了返回键,则Activity A从保存的状态中恢复。
  • 当用户通过点击Home键离开任务,当前Activity停止且它的任务栈调度到后台。系统保持了任务栈中每一个Activity的状态。如果随后用户点击了桌面图标,则该任务会被调度到前台并且恢复栈顶的Activity。
  • 如果用户点击了返回键,当前Activity将从任务栈中弹出并被销毁。在栈中的之前的Activity会被恢复。
  • Activity可以被实例化多次,且可以在不同任务栈中。

管理任务栈

  同上面的描述,Android管理任务和回退栈的方式是将连续启动的Activity放置在同一任务栈中,对于大多数的应用,这可以工作的很好,你不需要担心你的Activity和任务之间是怎样关联的或它们是怎样存在于任务栈中的。然而,你可以决定是否打断这种正常的行为。也许你想你的应用中的一个Activity在启动时创建一个新的任务,或是,当启动一个Activity时,你想将一个已经存在的实例移到栈顶,再或是,你想在离开任务时,将任务栈中除root Activity中的所有activity清除。
  你可以使用manifest中的<activity>元素的属性或传递到startActivity()的Intent中的flags,来实现这些需求。
  
与其相关的,主要的<activity>属性如下:

  • taskAffinity
  • launchMode
  • allowTaskReparenting
  • clearTaskOnLaunch
  • alwaysRetainTaskState
  • finishOnTaskLaunch

与其相关的主要的Intent flags有:

  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP

在下一节中,将给出怎样使用<activity>属性和Intent flags来定义activity和任务之间的关系与它们在回退栈中的行为表现。

  注意,大部分应用不应该打断Activity和任务之间的默认行为。如果你认为修改默认行为是必要的,那一定要测试该Activity的使用情况是否如你所愿,以确保其不会打断用户期待的行为。

定义启动模式

  启动模式允许你定义一个Activity的新实例怎样与当前任务关联。你可以用下面两种方式定义启动模式:

使用manifest文件

  当你在manifest文件中声明Activity时,你可以定义其启动时与任务的关联方式。
  具体可以使用<activity>元素的lauchMode属性来定义该Activity应该怎样在任务中创建。有四种不同启动模式可以设置给lauchMode属性。

  • standard
    默认设置。每次启动该种Activity时,系统在任务中创建一个新的Activity实例。这种Activity能够被实例化多次,每个实例属于不同的任务,每个任务可以有多个实例。
  • singleTop
    如果该Activity的一个实例存在与当前任务栈的栈顶,系统将启动Intent通过onNewIntent()传递给该实例,而不会新建实例。如果已有该实例不在栈顶,则会新建实例。该Activity会被实例化多次,每个实例可以属于不同的任务,每个任务可以有多个实例。
    注意,当该Activity的一个新实例被创建,用户可以点击返回键回到之前的Activity。但当一个Activity的已存在实例处理了这个启动Intent时,用户点击返回键不能回到调用onNewIntent()进行处理之前的状态。
  • singleTask
    该种启动模式的Activity仅会有一个实例。如果已有任务栈中存在该Activity实例,则系统会将启动它的Intent通过调用其onNewIntent()方法传递给它,而不会再创建一个新的实例,且该Activity上面的所有Activity将以合适的方式自动销毁。如果还没有该Activity实例,则其表现受taskAffinity属性影响,如果taskAffinity属性标识的任务不存在,则会新建一个任务,并将该Activity作为根Activity,如果taskAffinity属性标识的任务存在,则将该Activity压入该任务栈。
    注意,尽管Activity会被启动在一个新的任务中,点击返回键仍然能返回到之前的Activity。
  • singleInstance
    除了系统不会再将其他Activity放入该Activity所在任务,其他同singleTask一样。即该Activity是其所在任务的唯一成员,任何由它启动的Activity将被放置在分隔的任务栈中。

不管一个Activity是否启动在一个新的任务中还是在与启动它的Activity相同的任务栈中,点击返回键时,都会回到前一个Activity。然而,如果你启动的是singleTask模式的Activity,且如果其实例存在于后台,则整个任务会被带到前台。这时,回退栈将包含所有从后台带到前台的Activity,并且被放置在栈顶。如下图所示:
这里写图片描述

使用Intent flag

  当你调用startActivity()时,你可以在Intent中设置flag来声明启动的Activity与任务的关联方式。
  像这样,如果Activity A启动了Activity B,Activity B能在manifest中定义它应该与当前任务栈怎样关联,并且Activity A也可以请求Activity B怎样与当前任务关联。如果两个全部定义了,则Activity A的请求是优于Activity B的请求。
  可以用来修改默认行为的flag有:

  • FLAG_ACTIVITY_NEW_TASK
    其行为同launchMode设置为“singleTask”。
  • FLAG_ACTIVITY_SINGLE_TOP
    其行为同launchMode设置为“singleTop”。
  • FLAG_ACTIVITY_CLEAR_TOP
    如果被启动的Activity已经存在于当前任务中,则其上的所有Activity都被销毁,启动Intent传递到onNewIntent()方法,来恢复该Activity。
    没有对应的launchMode属性。

FLAG_ACTIVITY_CLEAR_TOP经常和FLAG_ACTIVITY_NEW_TASK一起使用。当它们一起使用时,这些flags是将一个已经存在的Activity放置到另一个任务中,并将其放在一个能响应该Intent的位置上。
注意,如果被指定的Activity的启动模式是“standard”,则它将从任务栈中移除,并在它的位置处创建一个新的实例来处理这个Intent。这是因为,当启动模式是“standard”时,对于每一个新的Intent都会创建一个新的实例。

  注意,manifest中可获取的启动模式不一定在Intent的flag中可获取,同样的,Intent的flag中可获取的启动模式在manifest中不一定可以定义。

处理关系

  “关系”指示一个Activity属于哪个任务。默认的,所有来自同一个应用程序的Activity有相同的“关系”。所以默认情况下,同一应用程序的所有Activity属于统一任务。但是,你可以修改一个Activity的关系。在不同应用程序的Activity可以共享同一个“关系”,同一应用程序的的Activity可以分配不同的“关系”。
可以使用<activity>元素的taskAffinity属性来修改给定Activity的“关系”。
taskAffinity属性的值是一个字符串。系统使用包名来标识一个应用程序的默认任务“关系”。为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task。
  “关系”用于下面两种情况:

  • 当创建Activity的Intent包含FLAG_ACTIVITY_NEW_TASK标签时。
    默认情况下,一个新的Activity被创建在调用startActivity()方法的Activity所在任务中。它被压入调用者所在的回退栈中。然而,如果传递到startActivity()方法中的Intent的包含FLAG_ACTIVITY_NEW_TASK标签,则系统会根据条件找寻一个合适的任务来放置这个新的Activity。通常,它是一个新的任务。但是,不总是。如果已经存在一个与这个新的Activity标识的“关系”相同的任务,则这个Activity被创建到这个任务中。否则,启动一个新任务。
    有些实体(比如通知栏管理器)会一直在一个外部任务中启动Activity,所以它们一直在传递到startActivity()方法中的Intent中设置FLAG_ACTIVITY_NEW_TASK标签。如果你有一个Activity被外部使用启动,则可能使用了这个标签,注意这是用户有独立的方式返回到启动它的任务,比如点击桌面图标。

  • 当Activity的allowTaskReparenting属性设置为true时。
    这种情况下,当该Activity标识的“关系”的任务返回到前台时,该Activity可以从启动它的任务移动到同其“关系”的任务中。
    例如,假设一个报导天气条件的Activity被定义为一个旅游应用的一部分,且其具有其所在应用程序的其他Activity相同的“关系”(应用程序的默认关系)并允许使用allowTaskReparenting属性设置允许re-pareting。当你的Activity之一启动了这个天气预报Activity时,它初始属于你的Activity的任务。但是,当这个旅游应用的任务返回前台时,这个天气预报Activity被重新安排到旅游应用的任务中并展示它。

清理回退栈

  如果用户长时间离开一个任务,则系统会清理掉任务中除根Activity之外的所有Activity。但用户再次回到任务中,仅根Activity是被恢复。系统表现这种行为的原因是,用户离开很久后,可能已经放弃了他们之前正在进行的操作,所以返回到任务开始一个新的操作。
  有很多的Activity属性可以用来修改这个行为:

  • alwaysRetainTaskState
    如果任务中的根Activity的这个属性被设置为true,则上面被描述的默认行为不会发生。很长一段时间后,该任务仍保持所有Activity。
  • clearTaskOnLaunch
    如果任务中的根Activity的这个属性被设置为true,则当用户离开任务并返回时,该任务栈被清理直到根Activity。用户会一直以初始状态返回任务,甚至只是离开一小会。
  • finishOnTaskLaunch
    这个属性很像 clearTaskOnLaunch,但它操作在一个单独的Activity上,而不是整个任务上。它会导致任何Activity销毁,包括根Activity。当它被设置为true,该Activity仅存在当前会话任务中。如果用户离开后返回该任务,则它不在存在。

启动任务

  可以通过给一个Activity设置”android.intent.action.MAIN”和”android.intent.category.LAUNCHER”Intent 过滤器来将其设置为一个任务的入口。例如:

<activity ... >    <intent-filter ... >        <action android:name="android.intent.action.MAIN" />        <category android:name="android.intent.category.LAUNCHER" />    </intent-filter>    ...</activity>

  这种类型的Intent过滤器会为该Activity产生一个图标和标签展示在应用程序启动器中,以提供给用户一个方式去创建该Activity或在它创建后可以任意次回到其创建的任务。
  其第二个能力是重要的:用户必须能够在离开任务后,又能使用该Activity启动器回到它。因为这个原因,作为启动器的Activity应该仅在该Activity有ACTION_MAIN 和CATEGORY_LAUNCHER过滤器时,才使用singleTasksingleInstance这两个启动模式。例如,如果这两个过滤器没有添加,一个Intent创建了一个singleTaskActivity,初始化了一个任务,且用户在该任务上执行了很多操作,这时用户点击Home键。这个任务被放到后台不可见,这时用户没有了返回到这个任务的方法。这是因为,它不会显示在应用程序启动器中。

回退任务

  在启动一系列Activity后,可能会创建几个任务,其中每个任务在回退栈中作为一项,在用户点击返回键时,回退栈的默认回退情况(为对返回键处理重写等)是,先获得回退栈中栈顶的任务,然后弹出该任务栈栈顶的Activity实例,当该任务栈中的所有Activity实例都被弹出,则该任务从回退栈中弹出,并销毁,执行这个回退过程,直到回退到桌面。

四种启动模式的关键结论验证

launchMode:standard

  standard是默认的启动模式,所以Activity不设置launchMode,则其启动模式为standard

被启动Activity和启动Activity的taskAffinity相同

FirstActivity注册
 <activity android:name=".FirstActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter></activity>
SecondActivity注册
<activity android:name=".SecondActivity" />

验证1:该种Activity不启动新的任务,被启动的Activity被压入启动它的Activity所在的任务栈中

  执行FirstActivity启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
TaskRecord{27db6384 #3208 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity (has extras) }        Hist #1: ActivityRecord{395c8c83 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3208}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{cd3c76d 16254:com.example.sunxiaodong.taskandbackstack/u0a379}        Hist #0: ActivityRecord{3240b0d0 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3208}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity (has extras) }          ProcessRecord{cd3c76d 16254:com.example.sunxiaodong.taskandbackstack/u0a379}

  从任务栈情况可以得到,SecondActivity被压入FirstActivity所在的任务栈中。

验证2:每次启动该种Activity,系统会在任务中创建一个新的Activity实例

  执行FirstActivity启动SecondActivity,SecondActivity中再次启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
TaskRecord{2ab63d02 #3211 A=com.example.sunxiaodong.taskandbackstack U=0 sz=3}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #2: ActivityRecord{3c598601 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3211}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{18925050 13122:com.example.sunxiaodong.taskandbackstack/u0a379}        Hist #1: ActivityRecord{2d1693 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3211}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{18925050 13122:com.example.sunxiaodong.taskandbackstack/u0a379}        Hist #0: ActivityRecord{ddb9d9 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3211}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{18925050 13122:com.example.sunxiaodong.taskandbackstack/u0a379}

  从任务栈情况可以得到,任务栈中已存在SecondActivity实例的情况下,再启动SecondActivity还会创建一个新的SecondActivity实例压入栈顶。

被启动Activity和启动Activity的taskAffinity不同

验证1:如果被启动Activity的taskAffinity所标识的任务不存在,则该种Activity不能创建新任务

FirstActivity注册
 <activity android:name=".FirstActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter></activity>
SecondActivity注册
<activity            android:name=".SecondActivity"            android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />

  执行FirstActivity启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
TaskRecord{1abd4247 #3369 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #1: ActivityRecord{17e1a735 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3369}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{1c02e7c3 18114:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{3d5eef14 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3369}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{1c02e7c3 18114:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈情况得到,standard启动模式的Activity不会创建taskAffinity标识的新的任务。

验证2:如果被启动Activity的taskAffinity所标识的任务已存在,则被启动Activity的实例会放入启动其Activity所在任务栈中,而不管启动Activity是否在被启动Activity的taskAffinity标识任务中

FirstActivity注册
 <activity android:name=".FirstActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter></activity>
SecondActivity注册
<activity            android:name=".SecondActivity"            android:launchMode="singleTask"            android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />
ThirdActivity注册
<activity android:name=".ThirdActivity" />

  执行FirstActivity启动SecondActivity,SecondActivity启动ThirdActivity。

任务栈情况(执行adb shell dumpsys activity
Task id #3374      TaskRecord{1ac34ecf #3374 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=2}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }        Hist #1: ActivityRecord{18fa9f27 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3374}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }          ProcessRecord{3c0de43a 29526:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{43cba37 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3374}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{3c0de43a 29526:com.example.sunxiaodong.taskandbackstack/u0a387}    Task id #3372      TaskRecord{2a45d05c #3372 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #0: ActivityRecord{253e4bf4 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3372}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{3c0de43a 29526:com.example.sunxiaodong.taskandbackstack/u0a387}

  任务栈情况,符合验证的结论。

launchMode:singleTop

FirstActivity注册
 <activity android:name=".FirstActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter></activity>
SecondActivity注册
<activity            android:name=".SecondActivity"            android:launchMode="singleTop" />

验证1:被启动Activity在启动其Activity所在任务栈的栈顶,则不会创建被启动Activity的新实例

  执行FirstActivity启动SecondActivity,SecondActivity再启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
TaskRecord{35412fbd #3376 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #1: ActivityRecord{1fbbf35c u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3376}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{11ea5d03 30105:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{3456a7b u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3376}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{11ea5d03 30105:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈情况得到,启动模式为singleTop的被启动Activity在启动其Activity所在任务栈的栈顶时,不会创建新实例。

验证2:被启动Activity不在启动其Activity所在任务栈的栈顶,则会在启动Activity所在任务栈的栈顶创建新的被启动Activity实例

ThirdActivity注册
<activity            android:name=".ThirdActivity"            android:launchMode="singleTask"            android:taskAffinity="com.example.sunxiaodong.taskandbackstack.third" />

  执行FirstActivity启动SecondActivity,SecondActivity启动ThirdActivity,ThirdActivity再启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
Task id #3381      TaskRecord{20eb4d89 #3381 A=com.example.sunxiaodong.taskandbackstack.third U=0 sz=2}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }        Hist #1: ActivityRecord{1fdcca07 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3381}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{1cdc6d17 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3381}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }          ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3379      TaskRecord{36c5f18e #3379 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #1: ActivityRecord{3fc54f79 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3379}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{104fbd9a u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3379}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}

  启动模式为singleTop的其他启动情况与启动模式为standard的情况相同,不再给出验证。

launchMode:singleTask

验证1:如果被启动Activity的taskAffinity属性标识的任务为启动Activity所在任务,则不会新建任务

FirstActivity注册
 <activity android:name=".FirstActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter></activity>
SecondActivity注册
<activity            android:name=".SecondActivity"            android:launchMode="singleTask" />

  执行FirstActivity启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
TaskRecord{220c4e08 #3406 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #1: ActivityRecord{2606f228 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3406}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{1ced3387 30484:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{27f048cb u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3406}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{1ced3387 30484:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈情况可以得到,启动模式为singleTask的Activity并不是每次启动都会新建任务,当其taskAffinity属性所标识的任务为启动Activity所在任务时,不会新建任务,即其taskAffinity属性所标识的任务已存在时,不会创建新的任务。

验证2:如果被启动Activity的taskAffinity属性标识的任务不存在,则会新建任务

SecondActivity注册
<activity            android:name=".SecondActivity"            android:launchMode="singleTask"            android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />

  执行FirstActivity启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
Task id #3410      TaskRecord{3298bcfc #3410 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=1}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }        Hist #0: ActivityRecord{1c628411 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3410}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{1ed6d60b 23610:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3409      TaskRecord{3b856f85 #3409 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #0: ActivityRecord{29642a8a u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3409}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{1ed6d60b 23610:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈情况可以得到,如果被启动Activity的taskAffinity属性标识的任务不存在,则会新建任务。

验证3:如果被启动Activity在栈中上面还有其他Activity实例,则这些Activity将以合适的方式自动销毁

FirstActivity注册
<activity android:name=".FirstActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter></activity>
SecondActivity注册
<activity            android:name=".SecondActivity"            android:launchMode="singleTask"            android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />
ThirdActivity注册
<activity android:name=".ThirdActivity" />
FourthActivity注册
<activity            android:name=".FourthActivity"            android:launchMode="singleTask"            android:taskAffinity="com.example.sunxiaodong.taskandbackstack.fourth" />

  执行FirstActivity启动SecondActivity,SecondActivity启动ThirdActivity,ThirdActivity启动FourthActivity。

任务栈情况(执行adb shell dumpsys activity
Task id #3416      TaskRecord{36ee9249 #3416 A=com.example.sunxiaodong.taskandbackstack.fourth U=0 sz=1}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }        Hist #0: ActivityRecord{252b608a u0 com.example.sunxiaodong.taskandbackstack/.FourthActivity t3416}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }          ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3415      TaskRecord{19cb74e #3415 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=2}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }        Hist #1: ActivityRecord{18f7b294 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3415}          Intent { cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }          ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{1d6f71ff u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3415}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3413      TaskRecord{3e8006f #3413 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #0: ActivityRecord{1648bf23 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3413}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈情况可知,当前有3个任务,其中SecondActivity和ThirdActivity 在一个任务中,且ThirdActivity的实例在SecondActivity的实例之上。

  接着上面,执行FourthActivity启动SecondActivity。

任务栈情况(执行adb shell dumpsys activity
Task id #3419      TaskRecord{20698cd0 #3419 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=1}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }        Hist #0: ActivityRecord{28bfef87 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3419}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{722a5fc 10546:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3421      TaskRecord{2eb884c9 #3421 A=com.example.sunxiaodong.taskandbackstack.fourth U=0 sz=1}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }        Hist #0: ActivityRecord{cd70e2d u0 com.example.sunxiaodong.taskandbackstack/.FourthActivity t3421}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }          ProcessRecord{722a5fc 10546:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3418      TaskRecord{197bf7ce #3418 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #0: ActivityRecord{270d8dc9 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3418}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{722a5fc 10546:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈的情况可知,SecondActivity启动后,其所在任务中的ThirdActivity销毁了,SecondActivity被放置在了栈顶。

launchMode:singleInstance

FirstActivity注册
<activity android:name=".FirstActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter></activity>

验证1:该种Activity的任务中,只会有一个实例,且由该种Activity启动Activity,如果被启动Activity的taskAffinity属性标识的任务存在,则将实例压入该任务中,如果不存在,则新建该任务

ThirdActivity注册
<activity android:name=".ThirdActivity" />

  执行FirstActivity启动SecondActivity,SecondActivity启动ThirdActivity。

任务栈情况(执行adb shell dumpsys activity
Task id #3423      TaskRecord{193241ab #3423 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #1: ActivityRecord{1b89f8e8 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3423}          Intent { flg=0x10400000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }          ProcessRecord{92fe3a1 13471:com.example.sunxiaodong.taskandbackstack/u0a387}        Hist #0: ActivityRecord{26f251dd u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3423}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{92fe3a1 13471:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3425      TaskRecord{304529c6 #3425 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }        Hist #0: ActivityRecord{2f0cb55d u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3425}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{92fe3a1 13471:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈中情况可知,SecondActivity启动的ThirdActivity的taskAffinity属性标识的任务存在,则不再新建任务,而是将其压入已存在的任务中。

ThirdActivity注册
<activity            android:name=".ThirdActivity"            android:taskAffinity="com.example.sunxiaodong.taskandbackstack.third" />

  给上面的ThirdActivity设置android:taskAffinity属性后,执行FirstActivity启动SecondActivity,SecondActivity启动ThirdActivity。

任务栈情况(执行adb shell dumpsys activity
Task id #3430      TaskRecord{666e0ca #3430 A=com.example.sunxiaodong.taskandbackstack.third U=0 sz=1}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }        Hist #0: ActivityRecord{a8a6e49 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3430}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }          ProcessRecord{3d776eb1 21693:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3429      TaskRecord{3887723b #3429 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}      Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }        Hist #0: ActivityRecord{d159cd9 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3429}          Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }          ProcessRecord{3d776eb1 21693:com.example.sunxiaodong.taskandbackstack/u0a387}Task id #3427      TaskRecord{1d7a3f96 #3427 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }        Hist #0: ActivityRecord{2cc6f9c u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3427}          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }          ProcessRecord{3d776eb1 21693:com.example.sunxiaodong.taskandbackstack/u0a387}

  从任务栈中情况可知,SecondActivity启动的ThirdActivity的taskAffinity属性标识的任务不存在,则会新建任务。

1 0