Android LaunchMode

页面跳转的时候,假如说之前已经有这个页面了,再次生成这个页面好像有点傻傻的,为什么不直接用前面已经生成的那个页面呢。这就要说到activity的启动模式。

android四种launchMode

AndroidManifest里设计了四种启动模式,分别是:

  1. standard
  2. singleTop
  3. singleTask
  4. singleInstance

standard 标准模式

默认的启动模式,如果不在Manifest.xml里面为某个activity指定android:launchMode,那个就默认是standard。这种模式下,每次都会创建新的实例。

这种模式下,谁启动了这个activity,那么这个Activity就运行在启动它的那个activity所在的栈中。

以Demo来举例,假如说有A,B,C三个Activity(其中A是MainActivity),顺序是A -> B -> C -> A,他们之前的跳转都使用startActivity(new Intent(xxx,xxx)),且不调用finish。

那么这个过程中任务栈是这样的:

standard launchMode

每次都是新生成一个实例。

如果在最后一个图之后,按下硬件的后退键,那么呈现的顺序就是从上到下的。

新建一个工程,让MainActivity的启动模式为standard,有个按钮按一下就启动MainActivity自己

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, MainActivity.class);
                startActivity(intent);
            }
        });
    }

程序启动后,按两下按钮。照理说现在栈里面应该有3个MainActivity实例。想个方法来验证一下

在终端里面执行命令adb shell dumpsys activity,打印出来很多信息,只要看下面一小段就行。

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #162
      TaskRecord{43d73e70 #162 A=jean.test.testtaskaffinity U=0 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #2: ActivityRecord{4331abe8 u0 jean.test.testtaskaffinity/.MainActivity t162}
          Intent { cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{43b92e90 585:jean.test.testtaskaffinity/u0a472}
        Hist #1: ActivityRecord{43f9e0d0 u0 jean.test.testtaskaffinity/.MainActivity t162}
          Intent { cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{43b92e90 585:jean.test.testtaskaffinity/u0a472}
        Hist #0: ActivityRecord{43f67ba8 u0 jean.test.testtaskaffinity/.MainActivity t162}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=jean.test.testtaskaffinity/.MainActivity bnds=[540,1215][804,1494] }
          ProcessRecord{43b92e90 585:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{43d73e70 #162 A=jean.test.testtaskaffinity U=0 sz=3}
        Run #2: ActivityRecord{4331abe8 u0 jean.test.testtaskaffinity/.MainActivity t162}
        Run #1: ActivityRecord{43f9e0d0 u0 jean.test.testtaskaffinity/.MainActivity t162}
        Run #0: ActivityRecord{43f67ba8 u0 jean.test.testtaskaffinity/.MainActivity t162}

从上面的信息可以知道,现在有两个任务栈,名字分别是com.huawei.android.launcher(桌面)和jean.test.testtaskaffinity(本文的示例程序)。

看到com.huawei.android.launcher这个栈里面只有一个Activity,就是桌面

看到jean.test.testtaskaffinity这个栈里面有三个Activity,都是MainActivity的实例


singleTop 栈顶复用

这种启动模式,会判断当前栈顶的Activity是不是要启动的Activity,如果是,则不创建新的而是直接引用这个Activity,如果不是,则创建新的Activity。

假如说有A,B,C三个Activity,每个都设置了android:launchMode="singleTop",那么结果如下,看上去和上面的standard好像没什么不同。

singleTop launchMode

但是,如果让B跳转到C的时候顺便finish自己,C跳转到A的时候顺便finish自己,那么结果如下:

C跳转到A需要启动A的时候,顺便finish了自己,由于A是singleTop模式,系统判断它是当前栈顶,则不生成新的Activity.

singleTop launchMode2

同样是上面那个程序,把MainActivity的启动模式改成android:launchMode="singleTop",点两次按钮,打印出来的信息如下:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #166
      TaskRecord{43ffeb98 #166 A=jean.test.testtaskaffinity U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #0: ActivityRecord{438651d0 u0 jean.test.testtaskaffinity/.MainActivity t166}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{43a7fdb0 28936:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{43ffeb98 #166 A=jean.test.testtaskaffinity U=0 sz=1}
        Run #0: ActivityRecord{438651d0 u0 jean.test.testtaskaffinity/.MainActivity t166}

看到jean.test.testtaskaffinity这个栈里面只有一个MainActivity的实例,验证了上面singleTop的说法。


singleTask

系统首先会检查是否存在想要的任务栈,若没有则创建该任务栈并创建activity实例并压入,若有这个任务栈,再检查这个栈里面是否有该Activity的实例,若没有则创建并压入,若有则清除其上的所有activity,让其置顶。

假如说有A,B,C三个Activity,只有A设置了android:launchMode="singleTask",其他都是默认的standard,那么结果如下,从C跳转到A的时候,由于A是singleTask,系统会检测栈中是否有A,如果有A则销毁A之上的其他Activity。

singleTask launchMode

同样是上面那个程序,把MainActivity的启动模式改成android:launchMode="singleTask",点两次按钮,打印出来的信息如下:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #169
      TaskRecord{43358550 #169 A=jean.test.testtaskaffinity U=0 sz=1}
      Intent { cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #0: ActivityRecord{44794e10 u0 jean.test.testtaskaffinity/.MainActivity t169}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{4335bbb8 26353:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{43358550 #169 A=jean.test.testtaskaffinity U=0 sz=1}
        Run #0: ActivityRecord{44794e10 u0 jean.test.testtaskaffinity/.MainActivity t169}

看到jean.test.testtaskaffinity这个栈里面只有一个MainActivity的实例

下面对这个程序,稍微做点儿变化,改成从MainAcvitity->TwoActivity->ThreeActivity->MainActivity。这几个Activity都是singleTask模式。

1.首先看从MainAcvitity->TwoActivity的任务栈情况

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #177
      TaskRecord{4467dde8 #177 A=jean.test.testtaskaffinity U=0 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #1: ActivityRecord{43306890 u0 jean.test.testtaskaffinity/.TwoActivity t177}
          Intent { cmp=jean.test.testtaskaffinity/.TwoActivity }
          ProcessRecord{44004b48 8314:jean.test.testtaskaffinity/u0a472}
        Hist #0: ActivityRecord{445b87e8 u0 jean.test.testtaskaffinity/.MainActivity t177}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{44004b48 8314:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{4467dde8 #177 A=jean.test.testtaskaffinity U=0 sz=2}
        Run #1: ActivityRecord{43306890 u0 jean.test.testtaskaffinity/.TwoActivity t177}
        Run #0: ActivityRecord{445b87e8 u0 jean.test.testtaskaffinity/.MainActivity t177}

可以看到,当启动singleTask模式的TwoActivity的时候,系统首先会检查是否存在想要的任务栈(jean.test.testtaskaffinity),此时有这个任务栈,则再检查这个栈里面是否有TwoActivity的实例,没有,则创建并压入。

2.再看TwoActivity->ThreeActivity

原理和上一步是一样的。可以看到现在站里面从底层到上层分别是MainActivity、TwoActivity、ThreeActivity

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #177
      TaskRecord{4467dde8 #177 A=jean.test.testtaskaffinity U=0 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #2: ActivityRecord{43cfefa0 u0 jean.test.testtaskaffinity/.ThreeActivity t177}
          Intent { cmp=jean.test.testtaskaffinity/.ThreeActivity }
          ProcessRecord{44004b48 8314:jean.test.testtaskaffinity/u0a472}
        Hist #1: ActivityRecord{43306890 u0 jean.test.testtaskaffinity/.TwoActivity t177}
          Intent { cmp=jean.test.testtaskaffinity/.TwoActivity }
          ProcessRecord{44004b48 8314:jean.test.testtaskaffinity/u0a472}
        Hist #0: ActivityRecord{445b87e8 u0 jean.test.testtaskaffinity/.MainActivity t177}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{44004b48 8314:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{4467dde8 #177 A=jean.test.testtaskaffinity U=0 sz=3}
        Run #2: ActivityRecord{43cfefa0 u0 jean.test.testtaskaffinity/.ThreeActivity t177}
        Run #1: ActivityRecord{43306890 u0 jean.test.testtaskaffinity/.TwoActivity t177}
        Run #0: ActivityRecord{445b87e8 u0 jean.test.testtaskaffinity/.MainActivity t177}

3.再看ThreeActivity->MainActivity。按照singleTask原理,系统里面有MainActivity需要的栈,且栈中有实例,则应该清除该实例之上的所有activity。

打印结果如下,印证了上面的推理过程。

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #177
      TaskRecord{4467dde8 #177 A=jean.test.testtaskaffinity U=0 sz=1}
      Intent { cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #0: ActivityRecord{445b87e8 u0 jean.test.testtaskaffinity/.MainActivity t177}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{44004b48 8314:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{4467dde8 #177 A=jean.test.testtaskaffinity U=0 sz=1}
        Run #0: ActivityRecord{445b87e8 u0 jean.test.testtaskaffinity/.MainActivity t177}

singleInstance

singleInstance这种启动模式和使用浏览器工作原理类似。在多个程序中访问浏览器时,如果当前浏览器没有打开,则打开浏览器,否则会在当前打开的浏览器中访问。申明为singleInstance的Activity会出现在一个新的任务栈中,而且该任务栈只存在这一个Activity。这种启动模式常用于需要与程序分离的界面。

假如说有A,B,C三个Activity,只有B设置了android:launchMode="singleInstance",其他都是默认的standard,那么结果如下,

singleInstance launchMode

当在最后一个图之后按硬件的后退键,那么呈现的顺序是B -> A -> C ->A -> 退出应用

图里面的结果也可以用adb shell dumpsys activity来验证

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="jean.test.testtaskaffinity">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:launchMode="standard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".TwoActivity"
                  android:launchMode="singleInstance">
        </activity>
        <activity android:name=".ThreeActivity"
                  android:launchMode="standard">
        </activity>
    </application>
</manifest>

1.启动应用,此时仅存MainActivity

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #178
      TaskRecord{43fcae10 #178 A=jean.test.testtaskaffinity U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #0: ActivityRecord{432fe9e0 u0 jean.test.testtaskaffinity/.MainActivity t178}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{4331f2f8 18019:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{43fcae10 #178 A=jean.test.testtaskaffinity U=0 sz=1}
        Run #0: ActivityRecord{432fe9e0 u0 jean.test.testtaskaffinity/.MainActivity t178}

2.MAinActivity -> TwoActivity。可以看到此时多了一个任务栈,且里面只有TwoActivity的实例。

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #179
      TaskRecord{44199180 #179 A=jean.test.testtaskaffinity U=0 sz=1}
      Intent { cmp=jean.test.testtaskaffinity/.TwoActivity }
        Hist #0: ActivityRecord{44198f00 u0 jean.test.testtaskaffinity/.TwoActivity t179}
          Intent { cmp=jean.test.testtaskaffinity/.TwoActivity }
          ProcessRecord{4331f2f8 18019:jean.test.testtaskaffinity/u0a472}

    Task id #178
      TaskRecord{43fcae10 #178 A=jean.test.testtaskaffinity U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #0: ActivityRecord{432fe9e0 u0 jean.test.testtaskaffinity/.MainActivity t178}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{4331f2f8 18019:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{44199180 #179 A=jean.test.testtaskaffinity U=0 sz=1}
        Run #1: ActivityRecord{44198f00 u0 jean.test.testtaskaffinity/.TwoActivity t179}
      TaskRecord{43fcae10 #178 A=jean.test.testtaskaffinity U=0 sz=1}
        Run #0: ActivityRecord{432fe9e0 u0 jean.test.testtaskaffinity/.MainActivity t178}

3.TwoActivity-ThreeActivity

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #2
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.huawei.android.launcher/.Launcher }
        Hist #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.huawei.android.launcher/.Launcher }
          ProcessRecord{43b899d0 3967:com.huawei.android.launcher/u0a43}

    Running activities (most recent first):
      TaskRecord{43c35040 #2 A=com.huawei.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{437243f8 u0 com.huawei.android.launcher/.Launcher t2}

  Stack #1:
    Task id #178
      TaskRecord{43fcae10 #178 A=jean.test.testtaskaffinity U=0 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
        Hist #1: ActivityRecord{44052ac8 u0 jean.test.testtaskaffinity/.ThreeActivity t178}
          Intent { flg=0x400000 cmp=jean.test.testtaskaffinity/.ThreeActivity }
          ProcessRecord{4331f2f8 18019:jean.test.testtaskaffinity/u0a472}
        Hist #0: ActivityRecord{432fe9e0 u0 jean.test.testtaskaffinity/.MainActivity t178}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=jean.test.testtaskaffinity/.MainActivity }
          ProcessRecord{4331f2f8 18019:jean.test.testtaskaffinity/u0a472}

    Task id #179
      TaskRecord{44199180 #179 A=jean.test.testtaskaffinity U=0 sz=1}
      Intent { cmp=jean.test.testtaskaffinity/.TwoActivity }
        Hist #0: ActivityRecord{44198f00 u0 jean.test.testtaskaffinity/.TwoActivity t179}
          Intent { cmp=jean.test.testtaskaffinity/.TwoActivity }
          ProcessRecord{4331f2f8 18019:jean.test.testtaskaffinity/u0a472}

    Running activities (most recent first):
      TaskRecord{43fcae10 #178 A=jean.test.testtaskaffinity U=0 sz=2}
        Run #2: ActivityRecord{44052ac8 u0 jean.test.testtaskaffinity/.ThreeActivity t178}
      TaskRecord{44199180 #179 A=jean.test.testtaskaffinity U=0 sz=1}
        Run #1: ActivityRecord{44198f00 u0 jean.test.testtaskaffinity/.TwoActivity t179}
      TaskRecord{43fcae10 #178 A=jean.test.testtaskaffinity U=0 sz=2}
        Run #0: ActivityRecord{432fe9e0 u0 jean.test.testtaskaffinity/.MainActivity t178}

注意:如果在一个singleTop或者singleInstance的Activity中通过startActivityForResult()方法来启动另一个Activity,那么系统会直接返回Activity.RESULT_CANCELED而不会再去等待返回。这是由于系统在Framework层做了对这两种启动模式的限制,因为Android开发者认为,不同Task之间,默认是不能传递数据的,如果一定要传递,那就只能通过Intent来绑定数据。


除了在AndroidManifest.xml里面可以通过给Activity设置android:launchMode来设置启动模式,还可以通过设置Intent的Flag来设置一个Activity的启动模式。(如果在AndroidManifest.xml和Intent里都设置了某个Activity的启动模式,则以Intent里的为准,即代码设置的优先级高于manifest里面的设置。)

有一些常用的Intent的Flag。这些flag是可以组合使用的,Intent有addFlag和setFlag两个方法来设置这些flag。

FLAG_ACTIVITY_NEW_TASK

使用一个新的task来启动一个Activity。

FLAG_ACTIVITY_SINGLE_TOP

使用singleTop模式来启动一个Activity.

FLAG_ACTIVITY_CLEAR_TOP

这个标识的作用是清除包含Activity的task中位于该Activity实例之上的其他Activity实例,效果等同于singleTask。

FLAG_ACTIVITY_NO_HISTORY

例如A启动B,B以这种模式启动C,C在启动D,则当前栈为ABD。即若Activity是以这种模式启动的,当该Activity启动其他Activity之后,该Activity就消失了。

FLAG_ACTIVITY_CLEAR_TASK

清除要启动的Activity所在的栈中的所有实例。一般是配合FLAG_ACTIVITY_NEW_TASK一起使用。

一般是在点击push消息需要进入应用的时候,Intent的这些flag有重要作用。

使用第三方push SDK,一般是在MainActivity里面进行绑定的。如果需要点击push消息,进入某个Activity。

如果是点击push消息,重新启动应用,那么设置如下:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK );

如果是点击push消息,进入指定的Activity,那么设置如下

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);


TaskAffinity

上面使用adb shell dumpsys activity打印了一些信息,里面有一些知识点和TaskAffinity有关。

TaskAffinity即任务相关性。标识了一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用包名。也可以由我们为每个Activity单独指定TaskAffinity

TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。

任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity处于暂停状态。

moveTaskToFront

alwaysRetainTaskState

clearTaskOnLaunch

finishOnTaskLaunch

栈的管理

当应用长时间置于后台,系统可能会清理应用Task栈中的Activity,当用户返回应用保留的只有应用的启动Activity。通过以下设置改变这种行为!

alwaysRetainTaskState: 如果栈底Activity的这个属性被设置为true,Task中的所有activity将被长时间保存。
clearTaskOnLaunch:如果栈底activity的这个属性被设置为true,一旦用户离开Task, 则 Task栈中的Activity将被清空到只剩下栈底activity。这种情况刚好与 alwaysRetainTaskState相反。即使用户只是短暂地离开,task也会返回到初始状态 (只剩下栈底acitivty)。
finishOnTaskLaunch:与clearTaskOnLaunch相似,但它只对单独的activity起作用,而不是整个Task。它可以结束任何Activity,包括栈底的Activity。 当它设置为true时,当前的Activity只在当前会话期间作为Task的一部分存在, 当用户按下Home键重新点击图标启动应用,它将不存在。

参考

1.http://droidyue.com/blog/2015/08/16/dive-into-android-activity-launchmode/index.html

2.http://blog.csdn.net/liuhe688/article/details/6754323

3.http://blog.csdn.net/liuhe688/article/details/6761337

4.http://wangkuiwu.github.io/2014/06/26/IntentFlag/

5.http://www.jianshu.com/p/224e2479da18

Show Comments