细谈Activity四种启动模式

2021-04-13 16:19:16 浏览数 (1)

Activity作为四大组件之一,也可以说是四大组件中最重要的一个组件,它负责App的视图,还负责用户交互,而且有时候还经常其他组件绑定使用,可以说非常的重要。

虽然说我们天天都在使用Activity,但是你真的对Activity的生命机制烂熟于心,完全了解了吗?的确,Activity的生命周期方法只有七个(自己数-。 ),但是其实那只是最平常的情况,或者说是默认的情况。也就是说在其他情况下,Activity的生命周期可能不会是按照我们以前所知道的流程,这就要说到我们今天的重点了——Activity的启动模式:我们的Activity会根据自身不同的启动模式,自身的生命周期方法会进行不同的调用。

一、在将启动模式之前必须了解的一些知识:

在正式的介绍Activity的启动模式之前,我们首先要了解一些旁边的知识,这些知识如果说模糊不清,那么在讨论启动模式的时候会一头雾水(笔者亲身感悟)。

  1. 一个应用程序通常会有多个Activity,这些Activity都有一个对应的action(如MainActivity的action),我们可以通过action来启动对应Activity(隐式启动)。
代码语言:javascript复制
<action android:name="android.intent.action.MAIN" />
  1. 一个应用程序可以说由一系列组件组成,这些组件以进程为载体,相互协作实现App功能。
  2. 任务栈(Task Stack)或者叫退回栈(Back Stack)介绍:

3.1.任务栈用来存放用户开启的Activity。 3.2.在应用程序创建之初,系统会默认分配给其一个任务栈(默认一个),并存储根Activity。 3.3.同一个Task Stack,只要不在栈顶,就是onStop状态:

3.4.任务栈的id自增长型,是Integer类型。 3.5.新创建Activity会被压入栈顶。点击back会将栈顶Activity弹出,并产生新的栈顶元素作为显示界面(onResume状态)。 3.6.当Task最后一个Activity被销毁时,对应的应用程序被关闭,清除Task栈,但是还会保留应用程序进程(狂点Back退出到Home界面后点击Menu会发现还有这个App的框框。个人理解应该是这个意思),再次点击进入应用会创建新的Task栈。

  1. Activity的affinity:

4.1.affinity是Activity内的一个属性(在ManiFest中对应属性为taskAffinity)。默认情况下,拥有相同affinity的Activity属于同一个Task中。 4.2.Task也有affinity属性,它的affinity属性由根Activity(创建Task时第一个被压入栈的Activity)决定。 4.3.在默认情况下(我们什么都不设置),所有的Activity的affinity都从Application继承。也就是说Application同样有taskAffinity属性。 <application android:taskAffinity="gf.zy" 4.4.Application默认的affinity属性为Manifest的包名。

暂时就是这么多了,如果还有不妥的地方我会补充的。接下来我们来正式看Activity的启动模式:

二、Activity启动模式:

1. 默认启动模式standard:

该模式可以被设定,不在manifest设定时候,Activity的默认模式就是standard。在该模式下,启动的Activity会依照启动顺序被依次压入Task中:

上面这张图讲的已经很清楚了,我想应该不用做什么实验来论证了吧,这个是最简单的一个,我们过。

2. 栈顶复用模式singleTop:

在该模式下,如果栈顶Activity为我们要新建的Activity(目标Activity),那么就不会重复创建新的Activity。

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="zy.pers.activitytext">
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:taskAffinity="gf.zy"
        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=".TwoActivity"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="ONETEXT_TWOACTIVITY" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity android:name=".ThreeActivity">
            <intent-filter>
                <action android:name="ONETEXT_THREEACTIVITY" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>

这是我的第一个应用OneText的Mainfest结构,里面创建了三个Activity,我们把第二个Activity的模式设置为singleTop。

每个Activity界面都只有一个显示当前界面名称的TextView和一个用来组跳转的Button,所以应用OneText的功能就是从活动1跳转到活动2,活动2继续跳转活动2,代码就不给大家展示了,都能写出来。

我们发现在我们跳转到TwoActivity之后,点击跳转新的TwoActivity时候,他没有响应。

为了作对比,我们再把TwoActivity设置为standard,看一看效果:

我们发现创建了很多的TwoActivity。

同时我们打印上task的Id(我没有把所有周期方法都打印log):

发现他们全部都是来自一个Task。这个可以过。

应用场景:

开启渠道多,适合多应用开启调用的Activity:通过这种设置可以避免已经创建过的Activity被重复创建(多数通过动态设置使用,关于动态设置下面会详细介绍)

3. 栈内复用模式singleTask:

与singleTop模式相似,只不过singleTop模式是只是针对栈顶的元素,而singleTask模式下,如果task栈内存在目标Activity实例,则:

  1. 将task内的对应Activity实例之上的所有Activity弹出栈。
  2. 将对应Activity置于栈顶,获得焦点。

同样我们也用代码来实现一下这个过程:

还是刚才的那一坨代码,只是我们修改一下Activity1的模式为singleTask,然后让Activity2跳转到Activity3,让Activity3跳转到Activity1:

在跳回MainActivity之后点击back键发现直接退出引用了,这说明此时的MainActivity为task内的最后一个Activity。所以这个模式过。

应用场景:

程序主界面,我们肯定不希望主界面被多创建,而且在主界面退出的时候退出整个App是最好的设想。

耗费系统资源的Activity:对于那些及其耗费系统资源的Activity,我们可以考虑将其设为singleTask模式,减少资源耗费(在创建阶段耗费资源的情况,个人理解-。 )。

4.全局唯一模式singleInstance:

这是我们最后的一种启动模式,也是我们最恶心的一种模式:在该模式下,我们会为目标Activity分配一个新的affinity,并创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点。新的Task有且只有这一个Activity实例。 如果已经创建过目标Activity实例,则不会创建新的Task,而是将以前创建过的Activity唤醒(对应Task设为Foreground状态)

我们为了看的更明确,这次不按照上图的步骤设计程序了(没错,这几张图都不是我画的-。 !)。

我们先指定一下这次的程序:还是这三个Activity,这次Activity3设置为singleInstance,1和2默认(standard)。

然后我们看一下这个效果:

说一下我们做了什么操作:

首先由1创建2,2创建3,然后又由3创建2,2创建3,3创建2,然后一直back,图如下:

还请各位别嫌弃我-。 ,图虽然不好看,但是很生动形象。。。。具体说一下:这张图对应着我们上面的程序流程,黄色的代表Background的Task,蓝色的代表Foreground的Task。

我们发现back的时候会先把Foreground的Task中的Activity弹出,直到Task销毁,然后才将Background的Task唤到前台,所以最后将Activity3销毁之后,会直接退出应用。

但是有没有想过这样会出现一个问题,什么问题我们直接看图就好:

0 人点赞