launchMode 属性的四种启动模式案例分析

launchMode 属性的四种启动模式

接上一篇文章https://blog.csdn.net/nishigesb123/article/details/88911044


引子

之前提到了launchMode属性的四种模式,下面回顾一下。

通过AndroidManifest.xml中activity标签的属性launchMode中可以设置Activity的加载模式,一共有以下四种模式:

  1. standard:标准模式,以这种模式加载必定会构造一个新的Activity实例放到目标task中的activity栈顶,不管当前 task的栈顶是什么情况。
  2. singleTop: 与standard模式类似,区别在于加载activity会多个判断步骤。判断需要加载的新activity与当前 task栈顶的activity是不是同一个,相同的话就不再构造新的activity,并调用这个activity的newlnstance ()方法,不相同就还是会构造新的activity放到栈顶。
  3. singleTask:该种模式下,会创建一个新的task来加iactivity,并且这个task中只允许存在一个Activity的一个实例(以后可以加载其他activity的实例)
  4. SingleInstance:这种模式下,会创建一个新的task并且这个task中只能存在一个需要加载的这个Activity实例,即除了这个activity之外,不允许其他activity。

直接看概念对于对“栈”不是很理解的朋友,可能一时半会难以理解,下面通过一系列案例深刻的去领会一下四种模式的区别和内涵。

准备工作

我们需要准备两个Activity,添加两个按钮,并为每个按钮准备点击事件,参考代码如下

Activity1

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/TextViewA"
        android:text="This is TextViewA"
        android:gravity="center"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/AtoA"
        android:text="AtoA"
        android:gravity="center"
        android:onClick="AtoA"
        app:layout_constraintTop_toBottomOf="@id/TextViewA"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/AtoB"
        android:text="AtoB"
        android:onClick="AtoB"
        android:gravity="center"
        app:layout_constraintTop_toBottomOf="@id/AtoA"/>


</android.support.constraint.ConstraintLayout>

Activity2 

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Main2Activity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/TextViewB"
        android:text="This is TextViewB"
        android:gravity="center"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/BtoA"
        android:text="BtoA"
        android:onClick="BtoA"
        android:gravity="center"
        app:layout_constraintTop_toBottomOf="@id/TextViewB"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/BtoB"
        android:text="BtoB"
        android:onClick="BtoB"
        android:gravity="center"
        app:layout_constraintTop_toBottomOf="@id/BtoA"/>
</android.support.constraint.ConstraintLayout>

接下来我们要完成定义的四个点击事件

代码非常简单,就是通过显式Intent,Activity跳转到另一个Activity

AtoB即从ActivityA(MainActivity)跳转到ActivityB(Main2Activity),其余同理。

    public void AtoA(View view){
        Intent intent = new Intent(this,MainActivity.class);
        startActivity(intent);
    }
    public void AtoB(View view){
        Intent intent = new Intent(this,Main2Activity.class);
        startActivity(intent);
    }
    public void BtoA(View view){
        Intent intent = new Intent(this,MainActivity.class);
        startActivity(intent);
    }
    public void BtoB(View view){
        Intent intent = new Intent(this,Main2Activity.class);
        startActivity(intent);
    }

下面正式进入测试,首先是

standard

首先,我们把配置清单文件的两个activity的launchMode换成standard(实际上默认就是这个,不加也没事)

下面是测试效果,可以看到,当点击ATOA的时候,虽然是当前Activity跳转到当前Activity,但是实际上却是通过新建Activity来实现的(可以发现点击的时候屏幕有出现加载Activity的过场动画——屏幕抖了一下),即在standard模式启动无论如何创建新的Activity实例。都会所以我们点击了三次AToA,需要点击四次返回才能回到主页。

然后我们再进行一组测试,交替点击ATOB和ATOA,再观察上面的提示文字(提示文字提示了当前处于的Activity),不难发现,返回的时候,ActivityA和B也是交替出现的,再次论证了我们的结论。

singleTop

接下来我们把配置清单文件的两个activity的launchMode换成singleTop,图就不截了

我们无论如何点击ATOA,界面都没有发生变化,点击返回立马回到home界面。这就和前面的默认模式不一样了——当加载的是当前Activity,singleTop并不会创建新的Activity。

我们先点击ATOB(有反应跳转到了ActivityB),然后在ActivityB点击了几次BTOB(没有反应)

到这里都没有什么问题,和之前的结论一样。

接下来再点击BTOA,回到了ActivityA,最后我们返回,发现顺序是A->B->A

即虽然回到了ActivityA,但是实际上和一开始的那个ActivityA并不是同一个,即创建了新的Activity。

这可能有点难以理解,但是和我们之前的结论并不矛盾,当加载的是当前Activity,singleTop并不会创建新的Activity。

注意体会“当前”两个字,所以最终我们的结论是:当加载的是当前Activity,singleTop并不会创建新的Activity,反之,则会创建新的Activity。

singleTask

接下来我们把配置清单文件的两个activity的launchMode换成singleTask

下面看图,图中测试分三部分。

第一部分:在activityA狂按AtoA,没有反应,点返回后直接退出。

第二部分:在activityA点AtoB切换到activityB,再在activityB狂按BtoB,没有反应,点返回回到A,再返回退出。

如此来看似乎和singleTop没有区别,然而,

第三部分:在activityA点AtoB切换到activityB,再在activityB点BtoA,切换回activityA,最后点了一下返回直接退出了。

实际上高版本的动画效果不明显,可以试试自定义切换动画,或者在低版本里测试。

实际上,可以发现,AtoB之后,BtoA的过程,不同于singleTop又创建了新的Activity,singleTask选择直接返回到之前的A。

对于栈中已有的活动,singleTask会进行复用。

更具体的理解“复用”,我们再来一组测试。

AtoB->BtoA->AtoB

点击返回返回到了A,再点击返回退出。

然而我们分析一下:

第一次操作AtoB,此时栈情况由下至上A-B

第二次操作BtoA,由于A已经存在,所以复用A,由于B是在A之后才进入的,所以B会被清理掉,此时栈中将会只有A

第三次操作AtoB,和第一次操作完全一样此时栈情况由下至上A-B

所以需要点击两次返回才能退出。

singleInstance

接下来我们把配置清单文件的两个activity的launchMode换成singleInstance

和之前的测试一样依旧分三部分

第一部分:在activityA狂按AtoA,没有反应,点返回后直接退出。

第二部分:在activityA点AtoB切换到activityB,再在activityB狂按BtoB,没有反应,点返回回到A,再返回退出。

到这里结果也完全一样。

第三部分:在activityA点AtoB切换到activityB,再在activityB点BtoA,切换回activityA,点一下返回,返回B,再点一下才退出。

再看两组测试。

第一组直接见过面的,就是AtoB,BtoA,AtoB三次操作,结果是点了两下返回就回到了主页。

第二组,我们交替切换AB,切换多少次数不清了,然而结果依旧是点了两下返回主页。

其实仔细观察,在这种模式下,Activity切换的动画效果非常“特别”,是不是很像点击了任务切换按钮切换了任务时的样子。

没错,回忆下对SingleInstance的介绍,实际上,在该模式下,并非新建Activity,而是新建Task,在新的Task里新建Activity。

如果加载的不是当前Activity,Activity总是会在新的task中运行

然后我们就可以试着去得出结论了。

首先,对于加载的是当前Activity,显然SingleInstance也不会去创建新的Activity

对于加载的不是当前Activity,新建Task,在新的Task里新建Activity。

 

补充

可以通过Flags来设置Activity的启动模式,参考代码如下:

    public void Flags(View view){
        Intent intent = new Intent(this,Main2Activity.class);
        //设置Activity的启动模式,下为在新的任务栈中启动Activity,相当于singleTask
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

实际上效果和 launchMode 差不太多,像“FLAG_ACTIVITY_SINGLE_TOP”不用说也知道和singleTop类似把。

时间关系,就不一一演示了。

值得一提的是,当launchMode和setFlags同时存在时,后者优先级更高一些。

setFlags可选的参数比较多,可以参考这篇文章https://blog.csdn.net/berber78/article/details/7278408

或者参考API:https://developer.android.google.cn/reference/android/content/Intent.html#setFlags(int)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云无心鸟知还

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值