二、Activity 的启动模式

 

一、四种启动模式:

① standard(标准模式)

    这个是系统的默认模式。在这种模式下,每次启动一个 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在,并且谁启动了这个 Activity,那么这个 Activity 就运行在启动它的那个 Activity 所在的栈中。

eg:
// FirstActivity.java
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

// SecondActivity.java
Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intent);

// ThirdActivity.java
Intent intent = new Intent(ThirdActivity.this, FirstActivity.class);
startActivity(intent);

FirstActivity.java -> SecondActivity.java -> ThirdActivity.java -> FirstActivity.java:

执行 adb shell dumpsys activity:

可以看到结果中,只有一个名为 com.cfm.launchermodeActivity 的任务栈,并且每启动一个 activity,都会创建一个相应的实例。

问题引入:当我们使用 ApplicationContext 去启动 standard 模式的 Activity 的时候会报错,为什么? 因为 standard 模式的 Activity 默认会进入启动它的 Activity 所属的任务栈中,但是由于非 Activity 类型的 Context(如ApplicationContext)并没有所属的任务栈,所以就会报错。解决方法就是为待启动的 Activity 指定 FLAG_ACTIVITY_NEW_TASK 标记位,这样启动的时候就会为它创建一个新的任务栈。

② singleTop(栈顶复用模式)

    在这种模式下,如果新 Activity 已经位于任务栈的栈顶,那么此 Activity 不会被重新创建,同时它的 onNewIntent() 方法会被回调,通过此方法的参数我们可以得到当前请求的信息。由于这个 activity 并没有被重新创建,所以它的 onCreate()、onStart() 都不会被系统调用。

// FirstActivity.java
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

// SecondActivity.java
Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intent);

// ThirdActivity.java
Intent intent = new Intent(ThirdActivity.this,ThirdActivity.class);
startActivity(intent);

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.d("test", "onNewIntent() 被回调了");
}


在 AndroidManifest.xml 为 ThirdActivity 指定启动模式为 singleTop:
<activity android:name=".ThirdActivity"
    android:launchMode="singleTop">
</activity>

FirstActivity.java -> SecondActivity.java -> ThirdActivity.java ->ThirdActivity.java ->ThirdActivity.java:

Log日志:

结果可以看到,任务栈中只有一个 ThirdActivity 实例,并且 ThirdActivity 中的 onNewIntent() 方法被调用了两次。

③ singleTask(栈内复用模式)

    这是一种单实例模式,在这种模式下,只要 Activity 在要进入的任务栈中存在,那么多次启动此 Activity 都不会重新创建实例,和 singleTop 一样,系统也会回调 onNewIntent()。并且 singleTask 默认具有 clearTop 效果,也就是说如果这个 Activity 不在栈顶时,它会把它上面的 Activity 顶出栈以让自己处于栈顶位置。如果要进入的栈不存在就先创建相应的任务栈,然后再入栈。

// FirstActivity.java
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

// SecondActivity.java
Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intent);

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.d("SecondActivity", "onNewIntent() 被回调了");
}

// ThirdActivity.java
Intent intent = new Intent(ThirdActivity.this, SecondActivity.class);
startActivity(intent);

在 AndroidManifest.xml 为 SecondActivity 指定启动模式为 singleTask:
<activity android:name=".SecondActivity"
    android:launchMode="singleTask">
</activity>

FirstActivity.java -> SecondActivity.java -> ThirdActivity.java ->SecondActivity.java:

Log日志:

从结果可以看出,当第二次启动 SecondActivity 时,由于之前的任务栈中已经有了此实例,所以它就不会被再次创建,而是直接使用之前的实例并回调 onNewIntent() 方法,并且 SecondActivity 上面的 Activity 也会被出栈。

④ singleInstance(单实例模式)

    这是一种加强的 singleTask 模式,它除了具有 singleTask 模式的所有特性外,还加强了一点,那就是具有此模式的 Activity 只能单独地位于一个任务栈中,由于栈内复用特性(singleTask 中的特性),后续请求均不会创建新的 Activity,并且还会回调 onNewIntent() 方法。

// FirstActivity.java
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

// SecondActivity.java
Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intent);

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.d("SecondActivity", "onNewIntent() 被回调了");
}

// ThirdActivity.java
Intent intent = new Intent(ThirdActivity.this, SecondActivity.class);
startActivity(intent);

在 AndroidManifest.xml 为 SecondActivity 指定启动模式为 singleInstance:
<activity android:name=".SecondActivity"
    android:launchMode="singleInstance">
</activity>

FirstActivity.java -> SecondActivity.java -> ThirdActivity.java ->SecondActivity.java:

Log日志:

二、TaskAffinity(任务相关性):

    TaskAffinity 参数可以翻译为任务相关性,它标识了一个 Activity 所需要的任务栈的名字,默认情况下,所有 Activity 所需任务栈的名字为应用的包名。我们可以通过 TaskAffinity 属性来设置当前 Activity 的任务栈名称,这个属性主要和 singleTask 启动模式和 allowTaskReparenting 属性配合使用,在其它情况下没有意义。另外,任务栈分为前台任务栈和后台任务栈,后台任务栈中的 Activity 处于暂停状态,用户可以通过切换将后台任务栈再次调到前台。

    TaskAffinity + singleTask 模式:

    指定 Activity 启动后任务栈的名称。

    TaskAffinity + allowTaskReparenting 属性:

    allowTaskReparenting 属性的作用是 Activity 迁移。当 allowTaskReparenting 属性和 TaskAffinity 配合使用时,Activity 可以从一个任务栈迁移到另一个任务栈。迁移的规则是:从一个与该 Activity 的 TaskAffinity 属性不同的任务栈中迁移到与 该 Activity 的 TaskAffinity 属性相同的任务栈中。

    这个比较抽象,举个例子:应用 A 中的 Activity a 和应用 B 中的 Activity b。a 启动 b 时,当 b 的 allowTaskReparenting 属性为 false 时,b 会在 a 的任务栈上创建实例;当 b 的 allowTaskReparenting 属性为 true 时,因为 a 和 b 的 TaskAffinity 属性不同,所以 b 会从 a 的 task 中迁移到 b 中 TaskAffinity 所表示的任务栈,如果这时启动应用 B ,由于 B 的任务栈已经存在,所以直接就会进入 b 界面。

三、为 Activity 指定启动模式:

① 通过 AndroidManifest.xml 文件指定 “launchMode”属性,eg:

<activity android:name=".SecondActivity"
    android:launchMode="singleInstance">
</activity>

② 通过 java 代码在 intent 中设置标志位:

Intent intent = new Intent();
intent.setClass(FirstActivity.this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

    二者的区别为:优先级上,第二种比第一种高,当两个同时指定以第二种方式为准;其次,各自的限定范围有所不同,比如第一种无法直接为 Activity 设定 FLAG_ACTIVITY_CLEAR_TOP 标识,而第二种无法为 Activity 指定 singleInstance 模式。总的来说,在能满足自己的需求范围内,使用哪种方式都可以。

 

四、Intent 中常用的 FLAG:

① FLAG_ACTIVITY_CLEAR_TOP:

    这里分两种情况:

    a. 当设置的这个 activity 在当前的 Task 中存在,并且启动模式为 standard 而且没有为这个 intent 中设置 FLAG_ACTIVITY_SINGLE_TOP 标志,此时它会清除这个栈中在它之上的(包括它自己)所有的 activity,然后重新创建这个 activity;

    b. 当设置的这个 activity 在当前的 Task 中存在,并且启动模式不为 standard 或者为这个 intent 中设置了FLAG_ACTIVITY_SINGLE_TOP 标志,此时它会清除这个栈中在它之上的(不包括它自己)所有的 activity,然后将这个 activity 重新回到栈顶并调用它的 onNewIntent() 方法; 

② FLAG_ACTIVITY_SINGLE_TOP:

    效果和在 AndroidManifest.xml 中指定的 launchMode 为 singleTop 一样。

③ FLAG_ACTIVITY_SINGLE_TASK:

    效果和在 AndroidManifest.xml 中指定的 launchMode 为 singleTask一样。

④ FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:

    如果设置,新的 activity 不会在最近启动的 activity 的列表中保存。

 

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值