Android任务栈和Activity四种启动模式详解

0、dumpsys命令简介

dumpsys命令详情可以查看官方文档,这里只介绍本文用到的具体命令及参数。

在终端以下命令可以在终端输出包含“com.sahooz”的任务栈和Activity记录

adb shell dumpsys activity | grep com.sahooz

其中grep是Linux或者Mac的命令,Windows下应该是

adb shell dumpsys activity | findstr com.sahooz

输出示例(这里节选了其中一个任务栈【TaskRecord】):

TaskRecord{1671541 #317 A=com.sahooz.semail U=0 StackId=64 sz=2}
      affinity=com.sahooz.semail
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.sahooz.semail/.MainActivity}
      realActivity=com.sahooz.semail/.MainActivity
      Activities=[ActivityRecord{f8ec514 u0 com.sahooz.semail/.MainActivity t317}, ActivityRecord{e24a487 u0 com.sahooz.semail/.EditEmailActivity t317}]
      mRootProcess=ProcessRecord{f0ee827 15026:com.sahooz.semail/u0a91}
        Hist #1: ActivityRecord{e24a487 u0 com.sahooz.semail/.EditEmailActivity t317}
          Intent { act=android.intent.action.SENDTO dat=mailto: flg=0x13400000 cmp=com.sahooz.semail/.EditEmailActivity (has extras) }
          ProcessRecord{f0ee827 15026:com.sahooz.semail/u0a91}
        Hist #0: ActivityRecord{f8ec514 u0 com.sahooz.semail/.MainActivity t317}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.sahooz.semail/.MainActivity }
          ProcessRecord{f0ee827 15026:com.sahooz.semail/u0a91}
      TaskRecord{1671541 #317 A=com.sahooz.semail U=0 StackId=64 sz=2}
        Run #1: ActivityRecord{e24a487 u0 com.sahooz.semail/.EditEmailActivity t317}
        Run #0: ActivityRecord{f8ec514 u0 com.sahooz.semail/.MainActivity t317}
  ResumedActivity: ActivityRecord{b487fb3 u0 com.sahooz.sms/.MainActivity t298}
    Proc # 2: fore  T/A/TOP  trm: 0 12387:com.sahooz.sms/u0a92 (top-activity)
    Proc # 0: prev  B/ /LAST trm: 0 15026:com.sahooz.semail/u0a91 (previous)
  mPreviousProcess: ProcessRecord{f0ee827 15026:com.sahooz.semail/u0a91}

可以看到,这个任务栈中打开了两个Activity,分别是EditEmailActivity和MainActivity,其中EditEmailActivity位于栈顶。

1、任务栈的概念

要了解一个东西,首先要清楚它的概念。以下图文摘自官方文档:

任务是用户在执行某项工作时与之互动的一系列 Activity 的集合。这些 Activity 按照每个 Activity 打开的顺序排列在一个返回堆栈中。例如,电子邮件应用可能有一个 Activity 来显示新邮件列表。当用户选择一封邮件时,系统会打开一个新的 Activity 来显示该邮件。这个新的 Activity 会添加到返回堆栈中。

在当前 Activity 启动另一个 Activity 时,新的 Activity 将被推送到堆栈顶部并获得焦点。上一个 Activity 仍保留在堆栈中,但会停止。当 Activity 停止时,系统会保留其界面的当前状态。当用户按返回按钮时,当前 Activity 会从堆栈顶部退出(该 Activity 销毁),上一个 Activity 会恢复(界面会恢复到上一个状态)。堆栈中的 Activity 永远不会重新排列,只会被送入和退出,在当前 Activity 启动时被送入堆栈,在用户使用返回按钮离开时从堆栈中退出。因此,返回堆栈按照“后进先出”的对象结构运作。图 1 借助一个时间轴直观地显示了这种行为。该时间轴显示了 Activity 之间的进展以及每个时间点的当前返回堆栈。

Android任务栈和Activity四种启动模式详解_第1张图片

其中有一句话值得注意:堆栈中的 Activity 永远不会重新排列,只会被送入和退出。

任务是一个整体单元,当用户开始一个新任务或通过主屏幕按钮进入主屏幕时,任务可移至“后台”。在后台时,任务中的所有 Activity 都会停止,但任务的返回堆栈会保持不变,当其他任务启动时,当前任务只是失去了焦点,如图 2 所示。这样一来,任务就可以返回到“前台”,以便用户可以从他们离开的地方继续操作。举例来说,假设当前任务(任务 A)的堆栈中有 3 个 Activity,当前 Activity 下有 2 个 Activity。用户按主屏幕按钮,然后从应用启动器中启动新应用。主屏幕出现后,任务 A 转到后台。当新应用启动时,系统会启动该应用的任务(任务 B),该任务具有自己的 Activity 堆栈。与该应用互动后,用户再次返回到主屏幕并选择最初启动任务 A 的应用。现在,任务 A 进入前台,其堆栈中的所有三个 Activity 都完好如初,堆栈顶部的 Activity 恢复运行。此时,用户仍可通过以下方式切换到任务 B:转到主屏幕并选择启动该任务的应用图标(或者从最近使用的应用屏幕中选择该应用的任务)。

Android任务栈和Activity四种启动模式详解_第2张图片

直白地说,就是我们在最近任务列表界面(按下底部三个按键中的小方块弹出的界面)里面看到的,其实并不是一个个的App,而是一个个任务(Task),每个任务使用了一个栈来管理其中的Activity。

Android任务栈和Activity四种启动模式详解_第3张图片

2、Activity的四种启动模式

我们可以在manifest文件中使用使用 activity 元素的 launchMode 属性来设定Activity的启动模式,它的取值可以为以下四个值之一:

  1. “standard”:标准模式,也是默认模式。当我们没有显式地在清单文件里面指定activity的launchMode属性的时候,这个Activity就会以”standard“模式启动。该模式的特点是每次调用startActivity方法启动的时候都是新建一个Activity实例,并把此实例推入当前任务栈的栈顶。所以同一个Activity class可能会存在多个实例。

  2. “singleTop”:该启动模式与“standard”类似,区别如果当前任务栈栈顶的Activity正好是要启动的Activity类的实例,那么不会再创建新的Activity实例,而是调用当前实例的onNewIntent方法,把新的Intent传递给Activity实例对象。

  3. “singleTask”:在另外的任务栈里启动此Activity,如果其他任务栈中已经存在此Activity类的实例,那么不再创建新的实例,调用当前实例的onNewIntent方法,把新的Intent传递给Activity实例对象。在已经存在此Activity类的实例的情况下,如果此实例不在任务栈的栈顶,那么任务栈会对栈内的Activity进行出栈操作,直至目标Activity类的实例位于栈顶。

  4. “singleInstance”:与 “singleTask” 相似,不同的是,此启动模式下,目标Activity所在的任务栈有且仅有该Activity实例。

接下来我们将会分单App操作和跨App操作两种情况来探讨这四种启动模式的行为表现。

2.1 练习demo

新建一个工程,包含三个module:singleapp、semail、sms。其中singleapp用于测试单App操作,semail和sms用来测试跨App操作。

Android任务栈和Activity四种启动模式详解_第4张图片

2.2 standard模式

2.2.1 单App操作

在singleapp中创建两个Activity类:MainActivity和StandardActivity。其中MainActivity和StandardActivity中分别有一个按钮,点击跳转StandardActivity。
我们点击MainActivity中的按钮,跳转到一个StandardActivity,再点击StandardActivity中的按钮会再创建一个StandardActivity的实例:

Android任务栈和Activity四种启动模式详解_第5张图片

点击了3次“STARTAGAIN”按钮,此时任务栈里应该有4个StandardActivity的实例。dumpsys查看任务栈:

TaskRecord{845b91d #320 A=com.sahooz.singleapp U=0 StackId=67 sz=5}
      affinity=com.sahooz.singleapp
      ...
      TaskRecord{845b91d #320 A=com.sahooz.singleapp U=0 StackId=67 sz=5}
        Run #4: ActivityRecord{52bffb2 u0 com.sahooz.singleapp/.standard.StandardActivity t320}
        Run #3: ActivityRecord{180aa77 u0 com.sahooz.singleapp/.standard.StandardActivity t320}
        Run #2: ActivityRecord{b465187 u0 com.sahooz.singleapp/.standard.StandardActivity t320}
        Run #1: ActivityRecord{dd4b7bb u0 com.sahooz.singleapp/.standard.StandardActivity t320}
        Run #0: ActivityRecord{d42342e u0 com.sahooz.singleapp/.MainActivity t320}
    mResumedActivity: ActivityRecord{52bffb2 u0 com.sahooz.singleapp/.standard.StandardActivity t320}
  ResumedActivity: ActivityRecord{52bffb2 u0 com.sahooz.singleapp/.standard.StandardActivity t320}
    Proc # 2: fore  T/A/TOP  trm: 0 16827:com.sahooz.singleapp/u0a93 (top-activity)

OK,没问题。

2.2.2 跨App操作

semail module中新建创建MainActivity和StandardEmailActicty,并在清单文件中对StandardEmailActivity作如下配置:

<activity 
    android:name=".StandardEmailActivity"
    android:label="Standard">
    <intent-filter>
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="mailto" />
        <category android:name="android.intent.category.DEFAULT" />
    intent-filter>
activity>

sms module中创建MainActivity,并增加一个按钮,其点击事件是打开一个发送邮件的隐式意图,以对应上面的清单文件配置:

fun sendEmail(v: View) {
    val intent = Intent(Intent.ACTION_SENDTO).apply {
        data = Uri.parse("mailto:")
        putExtra(Intent.EXTRA_EMAIL, "[email protected]")
    }
    if (intent.resolveActivity(packageManager) != null) {
        startActivity(intent)
    }
}

这是,分别安装两个App,并运行sms,不运行semail。点击sms的按钮,然后在弹出来的对话框里选择使用我们的semail发送邮件:

Android任务栈和Activity四种启动模式详解_第6张图片

可以看到,虽然打开了两个App,但是在最近任务列表里面只有一个任务,dumpsys命令查看:

TaskRecord{195ef69 #337 A=com.sahooz.sms U=0 StackId=84 sz=2}
      ...
      TaskRecord{195ef69 #337 A=com.sahooz.sms U=0 StackId=84 sz=2}
        Run #1: ActivityRecord{e12ae u0 com.sahooz.semail/.StandardEmailActivity t337}
        Run #0: ActivityRecord{eaed2f5 u0 com.sahooz.sms/.MainActivity t337}
    Proc # 0: prev  B/ /LAST trm: 0 19806:com.sahooz.semail/u0a91 (previous)
    Proc # 4: cch   B/ /CAC  trm: 0 19748:com.sahooz.sms/u0a92 (cch-act)
  mPreviousProcess: ProcessRecord{d951925 19806:com.sahooz.semail/u0a91}

可以看到,属于不同App的两个Activity处于一个任务栈中。这时候,如果我们回到launcher界面,打开semail App,我们会发现打开的是它的MainActivity。这是因为semail的MainActivty和StandardEmailActivity处于不同的任务栈中。

2.3 singleTop模式

根据上面的叙述,singleTop和standard只有在栈顶已经存在目标Activity类的实例时才有区别,其他时候是一样的。
在singleapp中新增一个SingleTopActivity,并在界面上添加两个按钮,点击事件分别是:

fun startAgain(v: View) {
    startActivity(Intent(applicationContext, SingleTopActivity::class.java))
}

fun startMain(v: View) {
    startActivity(Intent(applicationContext, MainActivity::class.java))
}

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)

    Log.d("SingleTopActivity", "Receive new Intent.")
}

在清单文件中对SingleTopActivity作如下配置

<activity
    android:name=".singletop.SingleTopActivity"
    android:launchMode="singleTop" />

并在MainActivity中新增一个按钮用于跳转SingleTopActivity。来点点看吧:

Android任务栈和Activity四种启动模式详解_第7张图片

可以看到,我的操作是:MainActivty -> SingleTopActivity -> SingleTopActivity -> MainActivty -> SingleTopActivity。如果是standard模式,那么此时栈中应该存在5个Activity实例。但由于SingleTopActivity的启动模式是singleTop,所以SingleTopActivity -> SingleTopActivity这个过程不会创建新的实例,所以栈中应该只有4个Activity实例。

dumpsys命令查看:

TaskRecord{aaf7e47 #346 A=com.sahooz.singleapp U=0 StackId=93 sz=4}
      ...
      TaskRecord{aaf7e47 #346 A=com.sahooz.singleapp U=0 StackId=93 sz=4}
        Run #3: ActivityRecord{cafb8f6 u0 com.sahooz.singleapp/.singletop.SingleTopActivity t346}
        Run #2: ActivityRecord{ad7be21 u0 com.sahooz.singleapp/.MainActivity t346}
        Run #1: ActivityRecord{3d16179 u0 com.sahooz.singleapp/.singletop.SingleTopActivity t346}
        Run #0: ActivityRecord{8778098 u0 com.sahooz.singleapp/.MainActivity t346}
    mResumedActivity: ActivityRecord{cafb8f6 u0 com.sahooz.singleapp/.singletop.SingleTopActivity t346}
  ResumedActivity: ActivityRecord{cafb8f6 u0 com.sahooz.singleapp/.singletop.SingleTopActivity t346}
    Proc # 2: fore  T/A/TOP  trm: 0 20666:com.sahooz.singleapp/u0a93 (top-activity)

结果符合预期。

注意:singleTop只有目标Activity类的实例位于栈顶的时候才不会创建新的实例,否则就算任务栈中已经存在目标Activity类的实例也还是会创建新的实例。

至于跨App操作,通过两者的区别很容易就推断出singleTop的行为了,有兴趣的同学自行实践一下。

2.4 singleTask模式

2.4.1 单App操作

在singleapp中新增一个SingleTaskActivity,并在界面上添加两个按钮,点击事件分别是:

fun startAgain(v: View) {
    startActivity(Intent(applicationContext, SingleTaskActivity::class.java))
}

fun startMain(v: View) {
    startActivity(Intent(applicationContext, MainActivity::class.java))
}

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)

    Log.d("SingleTaskActivity", "Receive new Intent.")
}

在清单文件中对SingleTaskActivity作如下配置

<activity
    android:name=".singletask.SingleTaskActivity"
    android:launchMode="singleTask"
    android:taskAffinity="com.sahooz.singleapp.singletask"/>

Note:taskAffinity属性后续会讲到

再在MainActivity中新增一个按钮用于跳转SingleTaskActivity。继续点点点。。。

首先我们按如下顺序操作:MainActivity -> SingleTaskActivity -> MainActivity,这时候,会有几个任务栈呢?最后启动的Activity位于哪个任务栈呢?dumpsys命令见分晓:

TaskRecord{e446271 #359 A=com.sahooz.singleapp.singletask U=0 StackId=106 sz=2}
      ...
      TaskRecord{e446271 #359 A=com.sahooz.singleapp.singletask U=0 StackId=106 sz=2}
        Run #1: ActivityRecord{6112bb3 u0 com.sahooz.singleapp/.MainActivity t359}
        Run #0: ActivityRecord{d35880c u0 com.sahooz.singleapp/.singletask.SingleTaskActivity t359}
    mResumedActivity: ActivityRecord{6112bb3 u0 com.sahooz.singleapp/.MainActivity t359}
    * TaskRecord{d828856 #357 A=com.sahooz.singleapp U=0 StackId=104 sz=1}
      ...
      TaskRecord{d828856 #357 A=com.sahooz.singleapp U=0 StackId=104 sz=1}
        Run #0: ActivityRecord{9fb00bf u0 com.sahooz.singleapp/.MainActivity t357}
  ResumedActivity: ActivityRecord{6112bb3 u0 com.sahooz.singleapp/.MainActivity t359}
    Proc # 1: fore  T/A/TOP  trm: 0 22260:com.sahooz.singleapp/u0a93 (top-activity)

MainActivity -> SingleTaskActivity的时候,还不存在SingleTaskActivity的实例,所以创建了一个并放到了新的任务栈中。SingleTaskActivity -> MainActivity的时候,因为MainActivity的启动模式是默认的standard,所以直接创建了一个新的实例并入栈到当前的任务栈。还是很好理解的。

接下来,再进行MainActivity -> SingleTaskActivity,也就是完整的操作链为MainActivity -> SingleTaskActivity -> MainActivity -> SingleTaskActivity,这时候又会有几个任务栈呢?1个?两个?还是3个?dumpsys。。。

* TaskRecord{e446271 #359 A=com.sahooz.singleapp.singletask U=0 StackId=106 sz=1}
      ...
      TaskRecord{e446271 #359 A=com.sahooz.singleapp.singletask U=0 StackId=106 sz=1}
        Run #0: ActivityRecord{d35880c u0 com.sahooz.singleapp/.singletask.SingleTaskActivity t359}
    * TaskRecord{d828856 #357 A=com.sahooz.singleapp U=0 StackId=104 sz=1}
      ...
      TaskRecord{d828856 #357 A=com.sahooz.singleapp U=0 StackId=104 sz=1}
        Run #0: ActivityRecord{9fb00bf u0 com.sahooz.singleapp/.MainActivity t357}
    Proc # 3: prev  B/ /LAST trm: 0 22260:com.sahooz.singleapp/u0a93 (previous)
  mPreviousProcess: ProcessRecord{ea270d7 22260:com.sahooz.singleapp/u0a93}

很明显,还是两个任务栈,这是为什么呢?根据singleTask的特性,最后的MainActivity -> SingleTaskActivity过程中,SingleTaskActivity实例已经存在,但不在栈顶,所以不创建新的实例,而是把栈顶的MainActivty出栈,让下面的SingleTaskActivity位于栈顶。

这是我们如果查看最近任务,就会发现如下图所示:

Android任务栈和Activity四种启动模式详解_第8张图片

也就是说,一个App可的Activity可以位于不同的任务栈中,不同App的Activity也可以在同一个任务栈中,这取决于业务逻辑。

2.4.2 跨App操作

semail中新建一个SingleTaskEmailActivity并在清单文件中作如下配置:

<activity android:name=".SingleTaskEmailActivity"
    android:launchMode="singleTask"
    android:label="SingleTask">
    <intent-filter>
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="mailto" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

我们进行如下操作:

我们先打开了semail的MainActivity的情况下,从sms跳转到SingleTaskEmailActivity,SingleTaskEmailActivity会与semail的MainActivity处在同一个任务栈。此时当我们按下返回键的时候,并没有返回sms,而是返回了semail的MainActivity,再次按下返回键的时候才返回到sms来。
打开了SingleTaskEmailActivity之后,如果我们没有按下返回键,而是先按下小方块查看最近任务或者按下Home键返回launcher,这时候再进入semail,按下返回键还是回到semail的MainActivity,但是再按返回键,不会再回到sms了,而是直接回到Launcher。这是有别于单App操作的地方。

2.4 singleInstance模式

singleInstance与singleTask几乎一样,不同的是在上一节的情况下,如果编写邮件的Activity启动模式是“singleInstance”,那么编写邮件的Activity不会和MainActivity在同一个任务栈里,而是在它自己单独的一个任务栈了,再启动其他Activity的时候,也不会入栈到它的任务栈里来。
singleInstance这里就不展示了,有兴趣的同学自己实践一下。

3、Mainfest中activity的各种属性

事实上,Activity的启动和任务栈的管理是相当复杂的。这里的复杂并不是三重积分那种想破脑袋都想不出来的复杂,而是细枝末节非常多,要完全搞清楚并不简单。Activity的启动行为除了和mainfest中指定的启动模式有关,还和activity元素的其他属性以及Intent中的Flags相关联。这里先说activity元素的相关属性。

3.1 taskAffinity和allowTaskReparenting

关于taskAffinity,官方描述在这里。Affinity意思是亲和性、相似性。在理想状态下,具有同样相似性也就是taskAffinity属性相同的Activity在同样的任务栈里,属于同一个任务。
通常来说,如果没有显式指定activity的taskAffinity,那么与application节点的taskAffinity一致,如果application节点的taskAffinity也没有显式地指定,那么就是app的包名了。

在测试singleTask的单个App操作的时候,我们使用了taskAffinity属性。如果在此例子中去掉taskAffinity的属性,打开SinglTaskAcitivity的时候,查看最近任务,我们会看到只有一个:

Android任务栈和Activity四种启动模式详解_第9张图片

这是因为SingleTaskActivity的启动模式是singleTask,需要保证的是SingleTaskActivity只有一个实例且位于栈顶,而不是一定要在不一样的任务栈,由于SingleTaskActivity的taskAffinity与当前任务栈亘Activity的taskAffinity相同(都是默认的包名),所以直接实例化并入栈到当前任务栈。

当activity的allowTaskReparenting属性被设置为true的时候,Activity可以在一个从任务栈转移到另外一个任务栈。举个例子,我们把StandardActivity的allowTaskReparenting:

可以看到,我们从sms启动StandardActivity的时候,它在sms默认的任务栈里,但是当我们回到Launcher然后点击启动semail的时候,它又到semail的任务栈去了。

值得注意的是,allowTaskReparenting本是为了提高在某些情况下的用户体验而设计的,但是在某些版本里并没有生效(我测试的Android 9),而且在某些版本表现也不太符合预期(我测试的Android 7偶尔出现启动semail后sms和semail没有StandardActivty都没有显示出来)。

3.2 其他属性

以下直接摘自官方文档:

如果用户离开任务较长时间,系统会清除任务中除根 Activity 以外的所有 Activity。当用户再次返回到该任务时,只有根 Activity 会恢复。系统之所以采取这种行为方式是因为,经过一段时间后,用户可能已经放弃了之前执行的操作,现在返回任务是为了开始某项新的操作。

您可以使用一些 Activity 属性来修改此行为:

  • alwaysRetainTaskState
    如果在任务的根 Activity 中将该属性设为 “true”,则不会发生上述默认行为。即使经过很长一段时间后,任务仍会在其堆栈中保留所有 Activity。
  • clearTaskOnLaunch
    如果在任务的根 Activity 中将该属性设为 “true”,那么只要用户离开任务再返回,堆栈就会被清除到只剩根 Activity。也就是说,它与 alwaysRetainTaskState 正好相反。用户始终会返回到任务的初始状态,即便只是短暂离开任务也是如此。
  • finishOnTaskLaunch
    该属性与 clearTaskOnLaunch 类似,但它只会作用于单个 Activity 而非整个任务。它还可导致任何 Activity 消失,包括根 Activity。如果将该属性设为 “true”,则 Activity 仅在当前会话中归属于任务。如果用户离开任务再返回,则该任务将不再存在。

4、Intent

以下摘自官方文档:

启动 Activity 时,您可以在传送给 startActivity() 的 intent 中添加相应的标记来修改 Activity 与其任务的默认关联。您可以使用以下标记来修改默认行为:

  • FLAG_ACTIVITY_NEW_TASK
    在新任务中启动 Activity。如果您现在启动的 Activity 已经有任务在运行,则系统会将该任务转到前台并恢复其最后的状态,而 Activity 将在 onNewIntent() 中收到新的 intent。
    这与上一节中介绍的 “singleTask” launchMode 值产生的行为相同。

  • FLAG_ACTIVITY_SINGLE_TOP
    如果要启动的 Activity 是当前 Activity(即位于返回堆栈顶部的 Activity),则现有实例会收到对 onNewIntent() 的调用,而不会创建 Activity 的新实例。
    这与上一节中介绍的 “singleTop” launchMode 值产生的行为相同。

  • FLAG_ACTIVITY_CLEAR_TOP
    如果要启动的 Activity 已经在当前任务中运行,则不会启动该 Activity 的新实例,而是会销毁位于它之上的所有其他 Activity,并通过 onNewIntent() 将此 intent 传送给它的已恢复实例(现在位于堆栈顶部)。
    launchMode 属性没有可产生此行为的值。

    FLAG_ACTIVITY_CLEAR_TOP 最常与 FLAG_ACTIVITY_NEW_TASK 结合使用。将这两个标记结合使用,可以查找其他任务中的现有 Activity,并将其置于能够响应 intent 的位置。

    注意:如果指定 Activity 的启动模式为 “standard”,系统也会将其从堆栈中移除,并在它的位置启动一个新实例来处理传入的 intent。这是因为当启动模式为 “standard” 时,始终会为新 intent 创建新的实例。

4、总结

standard和singleTop我们使用得比较多,在需要和其他App进行相互调用,比如说调用别的App的Activty或者提供一些Activty给别的App使用的时候,就有可能用到singletask和singleInstance。
总的来说,这里面最重要的还是Activity的四种启动模式,只要搞清楚了这个,其他的都比较好理解了。

你可能感兴趣的:(#,Android基础,Android,Android任务栈,Activity启动模式,四种启动模式,Activity四种启动模式)