zoukankan      html  css  js  c++  java
  • 细谈Activity四种启动模式

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

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

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

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

    1. 一个应用程序通常会有多个Activity,这些Activity都有一个对应的action(如MainActivity的action),我们可以通过action来启动对应Activity(隐式启动)。
    <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状态:

    image

    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中:

    image

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

    2. 栈顶复用模式singleTop:

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

    image

    <?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,代码就不给大家展示了,都能写出来。

    image

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

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

    image

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

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

    image

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

    应用场景:

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

    3. 栈内复用模式singleTask:

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

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

    image

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

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

    image

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

    应用场景:

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

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

    4.全局唯一模式singleInstance:

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

    image

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

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

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

    image

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

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

    image

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

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

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

    image

  • 相关阅读:
    查看Sql Server2016 是否激活
    MSSQL 账户访问视图权限的设置
    Vue 前端验证码
    (攻防世界) -- pwn入门 -- 新手区1 -- CGfsb
    .NET Core自动注册服务
    C# Graphics 生成文字圆形头像
    Codeforces Round #729 (Div. 2) C. Strange Function
    Codeforces Round #710 (Div. 3) ABCDE 题解
    Codeforces Round #708 (Div. 2) ABC1C2题解
    Codeforces Round #706 (Div. 2) D. Let's Go Hiking 博弈 思维
  • 原文地址:https://www.cnblogs.com/linhaostudy/p/14645830.html
Copyright © 2011-2022 走看看