深入了解Activity启动模式

与Activity密切相关的除了它的生命周期,还有它的启动模式。在学习Activity启动模式之前,我们先了解一下Activity任务栈。Android中是使用任务(Task)来管理Activity的,任务就是存放在栈里面的Activity的集合,这个栈就是任务栈。任务栈是一种先进后出的栈结构,当栈中没有Activity的时候,系统就会回收这个任务栈。明白任务栈的概念后,我们继续。

1.standard:标准模式
系统的默认模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的实例的生命周期符合典型情况下Activity的生命周期,它的onCreate,onStart,onResume都会被调用。这是一种典型的多实例实现,一个任务栈中可以有多个实例,每个实例可以属于不同的任务栈。在这种模式下,谁启动了这个Activity,那么这个Activity就会运行在启动它的那个Activity的任务栈中。

2.singleTop:栈顶复用模式
如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。需要注意的是,这个Activity的onCreate,onStart不会被系统调用,因为它没有发生改变。如果新Activity的实例已存在但不是位于栈顶,那么新Activity仍然会被重建。

3.singleTask:栈内复用模式
这是一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动Activity都不会重新创建实例,和singleTop一样,系统也会回调其onNewIntent。详细来说,当一个具有singleTask模式的Activity请求启动后,系统首先会寻找是否存在这个Activity想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建这个Activity的实例后放到栈中。如果存在这个Activity所需的任务栈,这时候看栈中是否存在这个Activity的实例,如果有实例存在,那么系统就会把这个Activity调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建这个Activity的实例并压入栈中。

4.singleInstance:单实例模式
这是一种加强的singleTask模式,如果某个Activity是singleInstance模式,当这个Activity启动以后,系统会为它创建一个新的任务栈,然后Activity独自在这个新的任务栈,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。

基本概念我们已经知道了,接下来举个例子深入了解这四种模式。


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="og.androidreview">

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

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity
            android:name=".FirstActivity"
            android:launchMode="standard" />
        <activity
            android:name=".SecondActivity"
            android:launchMode="singleTop" />
        <activity
            android:name=".ThirdActivity"
            android:launchMode="singleTask"
            android:taskAffinity="og.test"/>
        <activity
            android:name=".FourthActivity"
            android:launchMode="singleInstance" />
    application>

manifest>

5个Activity,MainActivity与FirstActivity均为标准启动模式,SecondActivity栈顶复用模式,ThirdActivity栈内复用模式,FourthActivity单实例模式。然后从MainActivity跳转到FirstActivity,FirstActivity跳转到SecondActivity,SecondActivity跳转到ThirdActivity,ThirdActivity跳转到FourthActivity,FourthActivity跳转到MainActivity,依次看看每一步发生了什么。

MainActivity–>FirstActivity
首先我在BaseActivity的onCreate()方法中使用getTaskId()打印该Activity所处的任务栈。MainActivity打印结果如下:
这里写图片描述
然后MainActivity跳转到FirstActivity,打印结果如下:
这里写图片描述
FirstActivity是标准模式,会进入到启动它的MainActivity的任务栈中,所以现在处于同一个任务栈中。
在Android Studio终端执行adb shell dumpsys activity命令,结果如下:
深入了解Activity启动模式_第1张图片
可以看到TaskId为164的任务栈的名称为og.androidreview,也就是我们包名。默认情况下,所有Activity所需任务栈的名字为应用的包名。此时栈中存在MainActivity与FirstActivity,并且FirstActivity是在MainActivity上面,符合任务栈的后进先出原则。

FirstActivity–>SecondActivity
深入了解Activity启动模式_第2张图片
可以看到,启动栈顶复用模式的SecondActivity,它也会被压入同一个任务栈中。
在Android Studio终端执行adb shell dumpsys activity命令,结果如下:
深入了解Activity启动模式_第3张图片
还是TaskId为164的任务栈,栈内从上到下依次为SecondActivity,FirstActivity,MainActivity。

SecondActivity–>ThirdActivity
深入了解Activity启动模式_第4张图片
前面我们提到过,当启动一个栈内复用模式的Activity后,系统首先会寻找是否存在这个Activity想要的任务栈。什么是这个Activity想要的任务栈,这里需要一个重要的参数TaskAffinity(任务相关性),它标识一个Activity所需要的任务栈的名字。我们可以为每个Activity都单独指定TaskAffinity,但是值不能和包名相同,否者就设置无效。TaskAffinity主要是和singleTask模式配合使用,在其他情况下没有意义。我在ThirdActivity的配置文件中,设置了TaskAffinity的值为og.test,也就是ThirdActivity想要的任务栈,而当前任务栈为og.androidreview,所以系统会创建一个新的TaskId为165的任务栈,ThirdActivity会单独运行在此任务栈中。
在Android Studio终端执行adb shell dumpsys activity命令,结果如下:
深入了解Activity启动模式_第5张图片
TaskId为164的任务栈,栈内从上到下依次为SecondActivity,FirstActivity,MainActivity。TaskId为165的任务栈,单独运行着ThirdActivity。

ThirdActivity–>FourthActivity
深入了解Activity启动模式_第6张图片
启动单实例模式的Activity,系统会创建一个新的TaskId为166的任务栈
在Android Studio终端执行adb shell dumpsys activity命令,结果如下:
深入了解Activity启动模式_第7张图片
TaskId为166的任务栈,单独运行着FourthActivity。

FourthActivity–>MainActivity
深入了解Activity启动模式_第8张图片
FourthActivity是单实例模式启动,任务栈中只能存在一个Activity实例,被启动的标准模式的MainActivity无法进入它的任务栈。
在Android Studio终端执行adb shell dumpsys activity命令,结果如下:
深入了解Activity启动模式_第9张图片
可以看到TaskId为164的任务栈,栈内从上到下依次为MainActivity,SecondActivity,FirstActivity,MainActivity。TaskId为165的任务栈,单独运行着ThirdActivity。TaskId为166的任务栈,单独运行着FourthActivity。从另一方面也说明了标准模式启动的Activity实例会被多次创建。

singleTask栈内复用模式的clear top功能
启动栈内复用模式的Activity会让它上面的Activity通通出栈,我们代码测验一下。
MainActivity为栈内复用模式,FirstActivity为标准模式,SecondActivity为标准模式。MainActivity跳转到FirstActivity,FirstActivity跳转到SecondActivity,SecondActivity跳转到MainActivity。我们看看它们生命周期的改变。
深入了解Activity启动模式_第10张图片
当从SecondActivity跳转到MainActivity的时候,FirstActivity执行了onDestroy,等MainActivity执行完onResume以后,SecondActivity也执行了onDestroy。是不是真的两个Activity都销毁了呢,我们此时按下返回键。
深入了解Activity启动模式_第11张图片
可以看到MainActivity也被销毁了,验证了栈内复用模式的clear top功能。

指定Activity启动模式的另外一种方法
我们除了在配置文件中为Activity指定启动模式,还可以在Intent中指定标志位来为Activity指定启动模式。这两种方法,后者优先级优于前者。当两者同时存在时,以后者为准。
还是上面的例子,我在配置文件中将MainActivity也设置为标准模式,在SecondActivity跳转到MainActivity的时候,代码这样写:

Intent intent = new Intent(SecondActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

singleTask栈内复用模式默认具有该标记为的功能。最后运行的结果和上面是一样的,这里就不贴图了。关于其他的标志位,大家可以自己查阅资料,项目里直接使用即可。

以上。如有错误不足的地方欢迎指出,随时改正。

你可能感兴趣的:(开发实战)