Activity启动模式SingleTask和Intent.FLAG_ACTIVITY_CLEAR_TOP区别__SkUnK的博客-程序员秘密

技术标签: android  Intent.FLAG_ACTIVITY_SINGLE_TO  singleTask  启动模式  Intent.FLAG_ACTIVITY_CLEAR_TOP  

Activity启动模式

介绍 Android 启动模式之前,先介绍两个概念task和taskAffinity

  • task:翻译过来就是“任务”,是一组相互有关联的 activity 集合,可以理解为 Activity 是在 task 里面活动的。 task 存在于一个称为 back stack 的数据结构中,也就是说, task 是以栈的形式去管理 activity 的,所以也叫可以称为“任务栈”。

  • taskAffinity:官方文档解释是:"The task that the activity has an affinity for.",可以翻译为 activity 相关或者亲和的任务,这个参数标识了一个 Activity 所需要的任务栈的名字。默认情况下,所有Activity所需的任务栈的名字为应用的包名。 taskAffinity 属性主要和 singleTask 启动模式或者 allowTaskReparenting 属性配对使用。

4种启动模式

  1. standard:标准模式,也是系统默认的启动模式,如果一个 Activity 的启动模式是 standard,则该 Activity 可以被多次实例化,且可以在不同的任务栈中存在。
    假如 activity A 启动了 activity B , activity B 则会运行在 activity A 所在的任务栈中。而且每次启动一个 Activity ,都会重新创建新的实例,不管这个实例在任务中是否已经存在。非 Activity 类型的 context (如 ApplicationContext )启动 standard 模式的 Activity 时会报错,因为非 Activity 类型的 context 并没有所谓的任务栈,所以系统会报错。此解决办法就是为待启动 Activity 指定 FLAG_ACTIVITY_NEW_TASK 标记位,这样启动的时候系统就会为它创建一个新的任务栈。这个时候待启动 Activity 其实是以 singleTask 模式启动的。

  2. singleTop:栈顶复用模式,如果一个 Activity 的启动模式是 singleTop,则该 Activity 可以被多次实例化,且可以在不同的任务栈中存在,且一个任务栈可以存在多个 singleTop启动模式的 activity。
    假如 activity A 启动了 activity B ,就会判断 A 所在的任务栈栈顶是否是 B 的实例。如果是,则不创建新的 activity B 实例而是直接引用这个栈顶实例,同时 B 的 onNewIntent 方法会被回调,通过该方法的参数可以取得当前 Intent 的信息;如果栈顶不是 activity B,则创建新的 activity B 实例压入栈(也就是一个任务栈存在多个实例)。

  3. singleTask:栈内复用模式。在第一次启动这个 Activity 时,系统便会创建一个新的任务栈,并且初始化 Activity 的实例,放在新任务栈的底部。但是,如果这个 Activity 已经存在于另一个任务栈中,则系统会销毁该 Activity 以上的所有Activity,然后调用该 Activity的 onNewIntent() 方法,不会创建新的实例。也就是说同一时刻只能存在一个该 Activity的实例。
    重要的一点就是 taskAffinity 属性。前面也说过了, taskAffinity 属性是和 singleTask 模式搭配使用的。

    4.singleInstance:单实例模式。这个是 singleTask 模式的加强版,它除了具有 singleTask 模式的所有特性外,它还有一点独特的特性,那就是此模式的 Activity 只能单独地位于一个任务栈,不与其他 Activity 共存于同一个任务栈。从这个 Activity 启动的任何其他Activity都会放到其他的任务栈。

还有一点:

无论 Activity 是在新任务栈中启动还是在相同的任务栈中启动,“返回”按钮始终会将用户带到上一个 Activity。但是,如果启动指定了 singleTask启动模式的 Activity,同时如果 后台 任务栈中存在该 Activity 的实例,则将整个任务栈内的 Activity 带到前台。此时,当前任务栈 现在包括在堆栈顶部提出的任务中的所有活动。如果不理解,下图说明这种情况。

 

通过上面我们了解了Activity的几种启动模式,接下来我们看看 SingleTask和 Intent.FLAG_ACTIVITY_CLEAR_TOP的区别:

singleTask:栈内复用模式。是一种单实例模式,在这种模式下,如果该Activity在栈中存在,那么多次启动此Activity都不会重新创建实例,而是销毁在它之上的所有Activity(不包括它本身),复用该Activity并调用它的onNewIntent方法,如果该Activity不存在,则创建该Activity并将其入栈到该Activity所需的任务栈中。

Intent.FLAG_ACTIVITY_CLEAR_TOP:销毁目标Activity和它之上的所有Activity,重新创建目标Activity,不会调用onNewIntent方法。

Intent.FLAG_ACTIVITY_SINGLE_TOP :当该activity处于栈顶时,可以复用,直接onNewIntent。

接下来我们看demo:

singleTask

在Manifest文件中我们将MainActivity指定为singleTask,

        <activity
            android:name=".MainActivity"
            android:configChanges="orientation"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity" />
        <activity android:name=".ThirdActivity"></activity>

在每个Activity的onCreate方法中打印栈信息:

    private String getTaskInfo(){
        StringBuilder builder = new StringBuilder();
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> taskInfos = am.getRunningTasks(10);
        for (ActivityManager.RunningTaskInfo task: taskInfos){
            builder.append("id= "+task.id+"\n");
            builder.append("description= "+task.description+"\n");
            builder.append("numActivityes= "+task.numActivities+"\n");
            builder.append("topActivity= "+task.topActivity+"\n");
            builder.append("baseActivity= "+task.baseActivity.toString()+"\n");
        }
        return builder.toString();
    }

MainActivity中设置一个Button启动SecondActivity:

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

SecondActivity中设置一个Button启动ThirdActivity:

Intent intent = new Intent(SecondActivity.this,ThirdActivity.class);
startActivity(intent);

SecondActivity中设置一个Button启动MainActivity,并传递消息:

Intent intent = new Intent(ThirdActivity.this,MainActivity.class);
startActivity(intent);

MainActivity的onNewIntent方法同样打印栈信息:

    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String taskInfo = getTaskInfo();
        Log.e(TAG, "onNewIntent: "+taskInfo);
    }

启动app,看打印出来什么东西

首先启动的是MainActivity,

MainActivity: onCreate: id= 1568
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    baseActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    id= 1559
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}
    baseActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}

可以看到MainActivity所在栈中Activity的数目numActivityes等于1,topActivity和baseActivity表示栈顶和栈底的Activity,

接下来启动SecondActivity,

SecondActivity: onCreate: id= 1568
    description= null
    numActivityes= 2
    topActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.SecondActivity}
    baseActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    id= 1559
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}
    baseActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}

可以看到栈中的Activity变为2

接下来启动ThirdActivity,

ThirdActivity: onCreate: id= 1568
    description= null
    numActivityes= 3
    topActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.ThirdActivity}
    baseActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    id= 1559
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}
    baseActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}

栈中的Activity变为3,

接着我们从ThirdActivity启动MainActivity,

MainActivity: onNewIntent: id= 1569
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    baseActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    id= 1559
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}
    baseActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}

我们发现这里只执行了onNewIntent方法,没有执行onCreate方法,说明服用了MainActivity,并且栈中只剩MainActivity,其他两个Activity都被销毁了。

Intent.FLAG_ACTIVITY_CLEAR_TOP

接下来我们把MainActivity的singleTask启动模式去掉(默认启动模式),并且ThirdActivity中启动MainActivity的代码如下:

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

前面的步骤不变,当我们从ThirdActivity启动MainActivity时,打印的信息如下:

MainActivity: onCreate: id= 1570
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    baseActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    id= 1559
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}
    baseActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}

执行的是onCreate方法,说明MainActivity被重新创建了,同时其他两个Activity也是被销毁。

Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_ACTIVITY_SINGLE_TOP

我们把ThirdActivity中的代码修改一下:

Intent intent = new Intent(ThirdActivity.this,MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

打印结果如下:

MainActivity: onNewIntent: id= 1571
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    baseActivity= ComponentInfo{com.example.hp.testtext/com.example.hp.testtext.MainActivity}
    id= 1559
    description= null
    numActivityes= 1
    topActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}
    baseActivity= ComponentInfo{com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity}

可以看到,使用Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_ACTIVITY_SINGLE_TOP时调用了onNewIntent方法,复用了MainActivity,说明他们可以实现和singleTask一样的效果

总结

singleTask会销毁目标Activity之上的Activity并复用已经存在的目标Activity(调用onNewIntent),但Intent.FLAG_ACTIVITY_CLEAR_TOP会连同目标Activity一起销毁,然后重新创建目标Activity。

singleTask是写死在Manifest文件中的,如果觉得太笨重,可以同时使用Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_ACTIVITY_SINGLE_TOP达到和singleTask一样的效果。

如果觉得不错顺手点个赞吧!!!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/XG1057415595/article/details/82192134

智能推荐

选择需要勇气_weixin_33862041的博客-程序员秘密

为什么80%的码农都做不了架构师?&gt;&gt;&gt; ...

aptitude管理维护工具_choujing8318的博客-程序员秘密

一、安装软件 sudo aptitude installquota #系统会自动安装软件依赖关系的包 二、重新安装一个软件 sudo aptitude reinstallquota 三、查询软件包信息 aptitude show...

mac使用brew安装mysql_brew 安装的mysql配置文件在哪_shibai906的博客-程序员秘密

mac使用brew安装mysql首先使用brew install [email protected]配置环境变量启动mysql设置密码首先使用brew install [email protected]如果想查看版本,直接使用brew search mysql.配置环境变量现在都安装了zsh,在vim ~/.zshrc配置环境变量。一般使用brew安装的文件都在:/usr/local/Cellar/下。我的mysql...

html控件、html服务器控件等的区别详解_weixin_30340745的博客-程序员秘密

asp.net之所以现在开发方便和快捷,关键是它有一组强大的控件库,包括web服务器控件,web用户控件,web自定义控件,html服务器控件和html控件等。这里我主要说说html控件、html服务器控件和web服务器控件的区别。 1、html控件:就是我们通常的说的html语言标记,这些语言标记在已往的静态页面和其他网页里存在,不能在服务器端控制的,只能在客户端通过javascript和...

区块链以太坊学习笔记_chen_hui.778的博客-程序员秘密

以太坊物联网区块链(一)Web3js 与 java 连接区块链可以参考我github上的两个小demoEthereum-javaEthereum-javascript搭建私有链, 利用以太坊平台完成数据上链如何搭建?用Geth搭建一个区块链节点,本地主机就和区块链网络中主机一致了,(可以连接main链,和其它测试链,还有自定义链)。注:可以通过赋予chainid和networkid不同的值让本机成为连接在main链chainid(1),测试链chanid(2-4)或者自定义链chainid(其它

FPGA模拟SENSOR,MIPI CSI-2发送图像到RV1126_sdi转mipi_anhuihbo的博客-程序员秘密

FPGA实现MIPI CSI-2发送,扩展了RV1126的视频输入接口。FPGA可实现LVDS,Cameralink,HDMI,SDI,自定义通信接口等向MIPI CSI的转换

随便推点

毕业设计matlab在误差处理中的应用,毕业设计matlab在误差处理中的应用.doc_weixin_39609622的博客-程序员秘密

毕业设计matlab在误差处理中的应用.doc 陕西理工学院毕业设计论文毕业论文任务书院系机械工程学院专业班级测控082级学生姓名马魁一、毕业论文题目MATLAB在误差理论中的应用二、毕业论文工作自_________年_____月_____日起至_________年月_____日止三、毕业论文进行地点陕西理工学院四、毕业论文内容要求传统的数据处理方法基于数理统计的理论,计算量较大,数据繁多。MAT...

Bootstrap的表格渲染_weixin_34032792的博客-程序员秘密

html &lt;div class="bootstrap-table"&gt; &lt;div class="fixed-table-container" style="padding-bottom: 0px;"&gt; &lt;div class="fixed-table-body"&gt; ...

区块链~Merkle Tree(默克尔树)算法解析~转载_瓦哥架构实战的博客-程序员秘密

/*最近在看Ethereum,其中一个重要的概念是Merkle Tree,以前从来没有听说过,所以查了些资料,学习了Merkle Tree的知识,因为接触时间不长,对Merkle Tree的理解也不是很深入,如果有不对的地方,希望各位大神指正*/Merkle Tree概念    Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树。Merkle树...

Android 魅族 线性马达 mEngine 震动适配_android 线性马达震动api_Night999的博客-程序员秘密

在点击事件中加入以下代码即可view.performHapticFeedback(31011);

java网络编程nio视频学习_weixin_32822759的博客-程序员秘密

java网络编程nio视频学习地址:https://www.bilibili.com/video/BV1Z4411C7iW?p=1

linux性能调分析及调优_-无-为-的博客-程序员秘密

linux性能调分析及调优http://blog.csdn.net/hn2002/article/details/7426907Linux 性能分析以及调优介绍    写在前面:计算机要解决的基本问题之一是如何在不增添更多硬件能力的情况下使其能够完成更多工作;而我们应用设计的一项重要伸缩性原则是:随着应用的推广和访问流量的增加,通过相应数量的服务器资源来应对;资源的消耗应该

推荐文章

热门文章

相关标签