Activity的四种launchMode

    |     2015年6月24日   |   Android UI界面   |     0 条评论   |    1164

今天要讲的是 Activity 的四种 launchMode。launchMode 在多个 Activity 跳转过程中很重要:是否生成新实例、是否重用已存在实例、是否和其他实例共用一个 task。task 是具有栈结构的对象,一个 task 可以管理多个 Activity;启动一个应用,也就创建与之对应的 task。

Activity 一共有以下四种 launchMode:

  • standard
  • singleTop
  • singleTask
  • singleInstance

在 AndroidManifest.xml 里把 android:launchMode 配成以上四种之一即可。下面结合实例一一介绍。


一、standard

standard 是默认启动模式,可以不配 android:launchMode,也可以显式指定为 standard。用名为 FirstActivity 的 Activity 演示。界面里的 TextView 显示当前实例序列号,Button 跳转到下一个 FirstActivity:

package com.scott.launchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class FirstActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first);
        TextView textView = (TextView) findViewById(R.id.textView);
        textView.setText(this.toString());
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}

连续点击几次按钮,会出现下面的现象:

都是 FirstActivity 的实例,但序列号不同;需要连续按后退键两次,才能回到第一个 FirstActivity。standard 模式原理如下:

每次跳转系统都会在 task 中生成一个新的 FirstActivity 实例,放在栈顶;按后退才能看到原来的实例。这就是 standard:不管有没有已存在的实例,都生成新的实例。


二、singleTop

在上面基础上为 FirstActivity 指定 android:launchMode=”singleTop”,系统就会按 singleTop 处理跳转。重复上面几个动作,现象如下:

结果和 standard 不同:三个序列号相同,用的是同一个 FirstActivity 实例;按一下后退程序立即退出,说明栈里只有一个实例。singleTop 原理:

跳转时系统先看栈顶是否已有 FirstActivity 实例,有则不再生成新的,直接使用。如果栈里有多个 Activity、目标不在栈顶会怎样?再新建 SecondActivity:

package com.scott.launchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class SecondActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second);
        TextView textView = (TextView) findViewById(R.id.textView);
        textView.setText(this.toString());
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}

把之前 FirstActivity 的跳转改成:

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

FirstActivity 跳到 SecondActivity,SecondActivity 再跳回 FirstActivity。演示结果:

两个 FirstActivity 的序列号不同,证明从 SecondActivity 跳回 FirstActivity 时生成了新实例。原理图:

从 SecondActivity 跳到 FirstActivity 时,系统发现存在 FirstActivity 实例,但不在栈顶,于是重新生成一个。这就是 singleTop:如果对应 Activity 实例正位于栈顶,则复用,不再生成新实例。


三、singleTask

在上面基础上把 FirstActivity 改成 android:launchMode=”singleTask”。演示结果:

过程中 FirstActivity 的序列号不变,SecondActivity 的序列号却不唯一:从 SecondActivity 跳到 FirstActivity 没有生成新实例,从 FirstActivity 跳到 SecondActivity 则生成了新实例。singleTask 原理图:

图下半部分是 SecondActivity 跳到 FirstActivity 后的栈变化:SecondActivity 消失了。系统发现已有 FirstActivity 实例,不再生成新的,而是把其上的 Activity 统统出栈,让 FirstActivity 变成栈顶、显示到幕前。

如果把 SecondActivity 也设为 singleTask,在本示例中其实无法保证它唯一:每次从 SecondActivity 跳到 FirstActivity,SecondActivity 都被迫出栈;下次 FirstActivity 再跳过来时找不到存在的实例,必须生成新的。但如果有 ThirdActivity,让 SecondActivity 和 ThirdActivity 互相跳转,SecondActivity 就可以保证唯一。

这就是 singleTask:如果发现有对应 Activity 实例,则使此实例之上的其他实例统统出栈,使它成为栈顶并显示到幕前。


四、singleInstance

这种模式比较特殊:会启用一个新的栈结构,把 Activity 放进去,并保证不再有其他 Activity 实例进入。把 FirstActivity 改回 launchMode=”standard”,SecondActivity 设为 singleInstance。因为涉及多个栈,需要在每个 Activity 里显示当前栈 id:

TextView taskIdView = (TextView) findViewById(R.id.taskIdView);
taskIdView.setText("current task id: " + this.getTaskId());

再演示这个流程:

这两个 Activity 实例分别被放在不同的栈结构中。singleInstance 原理图:

从 FirstActivity 跳到 SecondActivity 时,重新启用一个新栈来放 SecondActivity;按后退回到原始栈。图下半部分:在 SecondActivity 里再跳到 FirstActivity,系统会在原始栈里生成一个 FirstActivity 实例;然后回退两次并没有退出,而是回到了 SecondActivity——因为从 SecondActivity 跳出去时,起点变成了 SecondActivity 所在的栈,需要「回归」到这个栈。

如果把 FirstActivity 的 launchMode 改成 singleTop、singleTask、singleInstance 中的任意一个,流程将如图:

举个例子帮助理解:假如有一个 share 应用,ShareActivity 是入口、也是可供其他应用调用的 Activity,把它设为 singleInstance,然后在其他应用中调用。配置:

<activity android:name=".ShareActivity" android:launchMode="singleInstance">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SINGLE_INSTANCE_SHARE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

其他应用这样启动:

Intent intent = new Intent("android.intent.action.SINGLE_INSTANCE_SHARE");
startActivity(intent);

打开 ShareActivity 后再按后退回到原来界面时,ShareActivity 作为一个独立个体存在;这时再打开 share 应用,无需创建新实例即可看到结果,因为系统会查找,存在则直接利用。可以在 ShareActivity 里打印 taskId 看效果。过程原理图:

launchMode 是否新建实例 栈行为
standard 每次都新建 新实例入栈顶
singleTop 栈顶已有则复用 不在栈顶则仍新建
singleTask 任务栈里有则复用 其上实例全部出栈,使其到栈顶
singleInstance 单独占用一个栈 该栈里不允许再进其他 Activity

原文出处:Activity 的四种 launchMode。

一句话总结:standard 总是新建;singleTop 只复用栈顶;singleTask 复用栈内实例并清掉它上面的页面;singleInstance 独占一个新栈。

转载请注明来源:Activity的四种launchMode
本文链接地址:https://ai.zhousir.top/?p=806
回复 取消