带你深入理解Activity启动模式(LaunchMode)

我们知道默认情况下,当我们多次启动同一个activity时,系统会创建多个实例并把他们一个个放入任务栈,当我们按back键,这些activity又会一个个退出。在讲activity的launchmode之前,我们有必要了解下“任务栈(Task Stack)”这个概念。在Android中是使用任务(Task)来管理Activity的,任务就是存放在栈里面的Activity的集合,这个栈就是称为任务栈。

一,Activity的LaunchMode

明白任务栈的概念后,我们再来了解Activity的启动模式。目前Activity有四种启动模式:standard、singleTop、singleTask、singleInstance。下面我们一一介绍:

  • standard:标准模式,这是系统默认的默认,也就是说你不设置Activity的launchMode时,默认的就是standard。在这种模式下,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否存在。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈,但是这是有条件的,前提是启动它的Activity不能是singleInstance,因为singleInstance只能独立于一个任务栈中,不能有其他的Activity实例,这个后面我们会验证。比如非singleInstance模式的Activity A启动了标准模式的Activity B,那么Activity B就会进入到Activity A所在的任务栈。
  • singleTop:栈顶复用模式。在这种模式下,如果Activity已经在任务栈的栈顶了,当再次启动同一个Activity的时候,这个Activity不会被重新创建,而且它的onNewIntent()方法会被调用,但是它的onCreate()、onStart()方法不会被调用。此模式下的Activity也会进入启动它的非singleInstance模式的Activity所在的任务栈中。
  • singleTask:栈内复用模式。在这种模式下,只要Activity存在栈内,那么多次启动这个Activity都不会重新创建实例,系统会调用它的onNewIntent()方法。此外有个需要注意的地方:singleTask有clear top的效果,也就是说会将其以上的Activity全部出栈。
  • singleInstance:这是singleTask的一种加强模式,除了singleTask所有特性以外,具有此模式的Activity只能单独位于一个任务栈中。

二、实例讲解

介绍完四种启动模式后,我们看下各个模式的具体的例子。先介绍下背景:我们定义四个Activity,launchMode分别为:standard、singleTop、singleTask、singleInstance。对应的Activity的名称分别为:ActivityA、ActivityB、ActivityC、ActivityD。然后我们还定义了其各自的taskAffinity,这个参数标示了该Activity所需要的任务栈的名字,默认情况下,所有的Activity所需的任务栈的名字为应用的包名。先看代码,AndroidManifest定义如下:

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

    <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:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".launchmode.ActivityA"
            android:taskAffinity="com.jun.zhuzp.a1"
            android:launchMode="standard"/>
        <activity android:name=".launchmode.ActivityB"
            android:taskAffinity="com.jun.zhuzp.a2"
            android:launchMode="singleTop"/>
        <activity android:name=".launchmode.ActivityC"
            android:taskAffinity="com.jun.zhuzp.a3"
            android:launchMode="singleTask"/>
        <activity android:name=".launchmode.ActivityD"
            android:taskAffinity="com.jun.zhuzp.a4"
            android:launchMode="singleInstance"/>
    </application>

</manifest>

MainActivity是测试应用的主Activity,每个Activity中都有一个button,点击button就会去启动相应的Activity。我们在测试的过程中是这样的:MainActivity启动ActivityA,ActivityA启动ActivityB,ActivityB启动ActivityC,ActivityC启动ActivityD,然后ActivityD启动ActivityA,这样一个可以循环的过程。我们先看ActivityA的代码:

public class ActivityA  extends Activity{
    private static final String TAG = "ActivityA";
    private Button mSwitchButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate...");
        setContentView(R.layout.activity_launchmode);
        Log.d(TAG,"Task id = " + getTaskId());
        iniView();
    }

    private void iniView() {
        mSwitchButton = (Button)findViewById(R.id.btn_switch2);
        mSwitchButton.setText("启动ActivityB");
        mSwitchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClassName("com.jun.zhuzp.myapplication","com.jun.zhuzp.myapplication.launchmode.ActivityB");
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG,"onStart...");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d(TAG,"onNewIntent...");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume...");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy...");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop...");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause...");
    }
}

代码内容很简单,onCreate()方法中的getTaskId()用于打印该Activity所处的任务栈,然后就是对button设置了启动ActivityB的点击事件。其他几个Activity 的代码基本一样,只是button的点击事件不一样而已,这里就不贴代码了。接下来,我们来一步一步的分析我们写的测试效果。

  • standard模式的MainActivity启动ActivityA(说明:我在MainActivity的onCreate()方法中也加了getTaskId()的打印),我们先看下log

    我们我们可以看到,两个Activity的Task id 是一样的,这就是说明,ActivityA进入了MainActivity所在的栈,然后我们再看下adb shell dumpsys activity 命令下的的结果:

    我们可以看到Task id为89的任务栈的名称com.jun.zhuzp.myapplication。这是测试应用的包名,也是MainActivity任务栈名。但是我们在AndroidManifest文件中命名定义了ActivityA 的taskAffinity属性啊,它所在的任务栈仍然是MainActivity所在的任务栈,这是因为我们前面提到的:非singleInstance模式的Activity启动standard模式的Activity,被启动的Activity会进入启动它的那个Activity所在的任务栈中。那什么情况下,taskAffinity定义的任务栈才会起作用呢,想必大家也已经猜到了,就是singleInstance模式的Activity启动它时,才会创建一个名为taskAffinity所指定新的任务栈,这个结论会在singleInstance模式的ActivityD中启动standard ActivityA得到验证。

  • standard模式ActivityA启动singleTop模式的ActivityB。同样我们看log和adb shell dumpsys activity命令下的结果:

    和ActivityA类似,虽然为ActivityB设定了taskAffinity,但是ActivityB所在的任务栈仍然是MainActivity所在的任务栈,原因和前面standard模式一样。非singleInstance模式的Activity启动singleTop模糊的Activity,被启动的Activity会进入启动它的那个Activity所在的任务栈中,所以ActivityB和ActivityA在相同的任务栈中。

  • singleTop模式的ActivityB启动指定了taskAffinity的singleTask模式的ActivityC,照样先看logo和adb shell dumpsys activity结果:

    这个时候taskAffinity设定的任务栈名终于起作用了,这是为什么呢?因为当启动指定了任务栈的ActivityC时,系统会去判断ActivityC所需的任务栈名是否存在,如果不存在,就会创建其所需的任务栈,并将ActivityC压入创建的任务栈,这也就是上面所呈现的结果。那如果我们在AndroidManifest中没有设置ActivityC的android:taskAffinity属性时,那个ActivityC就是和ActivityA、ActivityB、MainActivity在同一个任务栈中。

  • singleTask模式的ActivityC启动singleInstance模式的ActivityD

    我们说过,singleInstance模式是singleTask的加强版,除了singleTask具有的特性外(这一点就在从logo和dumpsys activity结果可以看出),此种模式的Activity只能独立于一个任务栈中,这一点后面我们会验证。另外一点,如过没有指定singleInstance的任务栈名会怎样呢,系统还是会为它创建一个新的任务栈,任务栈名就是应用的包名,但是这并不表示没有指定任务栈名的ActivityD和MainActivity就在同一个任务栈中,虽然他们的任务栈名都是默认的应用包名,他们的Task id 是不一样的!!!

  • singleInstance模式ActivityD启动设置了taskAffinity属性的standard模式ActivityA

    这个时候,我们看到系统创建了一个新的任务栈——com.jun,zhuzp.a1。这就是我们为standard模式的ActivityA定义的taskAffinity指定的任务栈名,它终于起作用了!!!但是要铭记,它起作用的前提是singleInstance模式的Activity启动它,这是因为singleInstance模式任务栈中只能有一个Activity实例,standard模式的Activity想进也进不去啊,没办法系统只能再创建一个新的任务栈了,然后看到:额,还要个名字,那就给你命名吧。

  • 最后一点,我们来验证下singleTask模式的Activity具有clear top的功能,AndroidManifest文件,我们不变,我们改下启动Activity的方式:MainActivity—>ActivityC—>ActivityA—>ActivityB—>ActivityC。

    这是MainActivity—>ActivityC—>ActivityA—>ActivityB过程的任务栈情况,这个时候Task id为97的栈中有三个Activity,从栈顶到栈底依次是:ActivityB、ActivityA、ActivityC。singleTask模式的ActivityC在栈底。

    然后我们再执行ActivityB—>ActivityC时,任务栈的情况:Task id 为97的栈中只有ActivityC里,另外两个都已经出栈了,这就是singleTask具有的clear top 的功能。同时,这个时候也不会走Activity的onCreate()方法了,会走onNewIntent()方法。

补充:我们也可以在代码中通过给Intent来设置标志位来为Activity指定启动模式,例如:

Intent i = new Intent();
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setClassName("com.jun.zhuzp.myapplication","com.jun.zhuzp.myapplication.launchmode.ActivityA");
startActivity(i);

但是这种方式还是和在AndroidManifest中设置launchMode有差别的,首先设置Activity的flag的优先级比在AndroidManifest中定义的优先级高;其次他们也有各自的使用范畴,比如AndroidManifest中只能定义四中:standard、singleTop、singleTask、singleInstance;flag就是很多种,具体大家可以看下文档。

这里我们列举部分Flag讲解

FLAGE_ACTIVITY_NEW_TASK,这个标志位对应于AndroidManifest中设置的“singleTask”

FLAGE_ACTIVITY_SINGLE_TOP,这个标志位对应于AndroidManifest中设置的“singleTop”

FLAGE_ACTIVITY_CLEAR_TOP,当Activity设置此标志位后,启动它时,在同一任务栈中所有位于它之上的Activity都会出栈。比如栈自底向上依次是:MainActivity—ActivityA—ActivityB,各个Activity 的launchMode还是给出的AndroidManifest中的定义,这个时候如果再启动ActivityA,同时设置了flag为FLAGE_ACTIVITY_CLEAR_TOP。那么栈内的自底向上就成了这样:MainActivity—ActivityA(此ActivityA实例不是之前栈内的那个,而是新的,之前的已出栈)。

三,总结

上面就是有关Activity启动模式的主要内容了,最后,我们通过一系列的图来总结下,方便大家理解。

1,standard,标准模式,每次启动都会创建新的实例,不管实例是否存在

2,singleTop,栈顶复用,如果Activity处于栈顶,则不会创建新的Activity

3,singleTask,栈内复用,只要Activity在栈内存在,那么多次启动该Activity都不会创建新的Activity实例。默认具有clear top的效果。

4,singleInstance,在singleTask的基础上,限制了此模式的Activity只能单独地位于一个任务栈中。

好了,以上就是关于launchmode的全部内容了,如果不正确的地方,还望指正。欢迎转载,转载请注明出处:带你理解深入Activity启动模式(LaunchMode)http://blog.csdn.net/zhuzp_blog/article/details/51367477

时间: 2024-11-05 18:56:31

带你深入理解Activity启动模式(LaunchMode)的相关文章

深入Activity,Activity启动模式LaunchMode完全解析

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53221384 本文出自[DylanAndroid的博客] 深入Activity,Activity启动模式LaunchMode完全解析 在平时的开发中,我们可能会了解到Activity的任务栈还有Activity的启动模式.那么Activity的启动模式都分别是怎么样的呢?如果设置了这些启动模式对任务栈有事么影响 ,还有就是这么启动模式在实际的开发中有什么应用呢?这里用图例和d

深入理解Activity启动模式

今天看到这个,觉得还不错,于是乎收藏下 作者原创连接    共分3篇: 深入理解Activity启动模式(一)–Activity与进程,线程的关系 深入理解Activity启动模式(二)–Activity,回退栈,Task之间的关系 深入理解Activity启动模式(三)–Activity启动模式特点 概述 Android官网介绍Activity的启动模式时比较含糊,介绍Application,Activity,Task,Process,Thread等概念以及它们之间的关系时,也没有说得清楚.大

全面解析Activity启动模式(LaunchMode)

欢迎Follow我的GitHub, 关注我的CSDN. 在Android应用中, Activity是最核心的组件, 如何生成一个Activity实例, 可以选择不同的启动模式, 即LaunchMode. 启动模式主要包括: standard, singleTop, singleTask, singleInstance. 标准模式在每次启动时, 都会创建实例; 三种单例模式, 会根据情况选择创建还是复用实例. 在Activity启动中, 创建实例的生命周期: onCreate -> onStart

Activity启动模式launchMode

今天要讲得是Activity的四种启动模式launchMode属性,该属性用于配置该Activity的加载模式,该属性支持以下4个属性值. standard:标准模式,也是默认模式. singletop:Task栈顶单例模式. singleTask:Task内单例模式. singlestance:全局单例模式. 在继续写下去之前我想说一下,像launchMode这种基础的Android知识在网上已经有很多大神写得十分详细,为什么我还要写呢?我之所以写,是因为我确确实实是个菜鸟,将课本.网上大神的

Android 图文教学让你彻底理解activity启动模式

我们首先从最简单的开始, standard 这个模式就是默认的模式,我们都知道 当你用这个模式时,每次发送一个intent,都会生成一个新的实例! 我写一个简单的例子: 1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com

Activity启动模式(launchMode)详解

Activity 的启动模式有四种,standard.singleTop.singleTask.singleInstance. image.png 1.standard standard是Activity默认的启动模式,在不进行显示指定的情况下,所有活动都会自动使用这种启动模式. 每次启动都一个新的Activity位于栈顶. android:launchMode="standard",此时每次点击按钮都会创建新的Activity 现在,我们写一个简单的按钮 ,实现跳转Activity

我对standard、singleTop、singleTask和singleInstance四种Activity启动模式的理解

之前自学android的时候,单从视频和书本上对这四种启动模式仅仅有了初步的字面上的理解.最近实战了下,也对这四种启动模式有了比较清晰的概念. 首先说下什么是Activity,按照我的理解,我们在手机上看到的每一个页面都是一个Activity,包括系统的桌面,也是一个Activity. 要启动一个Activity有四种模式:standard(标准启动模式).singleTop.singleTask.singleInstance. 注: Aty1_1和Aty2_1为两个不同的Activity,At

Android中Activity启动模式详解,可以控制程序按home键后进来还会调用一个自己不喜欢的界面

其实这是很简单的一个问题.但是这还是要对android中activity的启动模式有相当的理解才行,当点击home键的时候,懂Android的人都知道,他会把当前activity放到后退栈中, 栈(Stack)又称堆栈,它是一种运算受限的线性表,其限制是仅允许在表的一端进行插入和删除运算.人们把此端称为栈顶,栈顶的第一个元素被称为栈顶元素,相对地,把另一端称为栈底.向一个栈插入新元素又称为进栈或入栈,它是把该元素放到栈顶元素的上面,使之成为新的栈顶元素:从一个栈删除元素又称为出栈或退栈,它是把栈

Android中Activity启动模式全面解析

在Android应用中, Activity是最核心的组件, 如何生成一个Activity实例, 可以选择不同的启动模式, 即LaunchMode. 启动模式主要包括: standard, singleTop, singleTask, singleInstance. 标准模式在每次启动时, 都会创建实例; 三种单例模式, 会根据情况选择创建还是复用实例. 在Activity启动中, 创建实例的生命周期: onCreate -> onStart -> onResume; 重用实例的生命周期: on