Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

任务栈 启动模式 Task Flag launchMode MD


目录

任务栈

Activity的四种启动模式

Activity启动模式有四种,可以根据实际的需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。

设置Activity的启动模式,只需要在AndroidManifest.xml里对应的activity标签设置android:launchMode属性。

只记住以下内容就够了:

  • standard:默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。
  • singleTop:可以有多个实例,但是不允许多个相同Activity叠加。即如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。
  • singleTask:只有一个实例。
    • 如果在同一个应用程序中启动它,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity全部destory掉并调用它的onNewIntent方法。
    • 如果是在别的应用程序中启动它(比如跳转到QQ),则会新建一个task,并在该task中启动这个Activity。
    • 可以使用singleTask来退出整个应用:将主Activity设为SingTask模式,然后在要退出的Activity中跳转到主Activity,然后重写主Activity的onNewIntent函数,并在函数中加上一句finish。
    • 注意:和singleInstance不同的是,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。
  • singleInstance:只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。

基本概念

栈(Stack)是一种常用的数据结构,栈只允许访问栈顶的元素,栈就像一个杯子,每次都只能取杯子顶上的东西,而对于栈就只能每次访问它的栈顶元素,从而可以达到保护栈顶元素以下的其他元素

"先进后出"或"后进先出"就是栈的一大特点,先进入栈的元素总是要等到后进入栈的元素出栈以后才能出栈。

递归就是利用到了系统栈,暂时保存临时结果,对临时结果进行保护.

栈的基本操作:压栈、弹栈

任务栈简单的说就是一组以栈的模式聚集在一起的Activity组件集合,类似于一个填充了Activity的容器,最先加入的Activity会处于容器最下面,最后加入的处于容器最上面,而从Task中取出Activity时是从最顶端先取出,最后取出的是最开始添加Activity,这就是后进先出模式。而Activity在Task中的顺序是可以控制的,在Activity跳转时用Intent Flag可以设置新建activity的创建方式。

Intent中常用的Flag

Flag表示Intent的标志位,常用于Activity的场景中,它和Activity的启动模式有着密切的联系。

下面列举的是和Activity启动模式相关的Flag属性:

  • FLAG_ACTIVITY_NEW_TASK:系统会检查当前所有已创建的Task中是否有该要启动的Activity的Task,若有,则在该Task上【创建】新的Activity;若没有则新建一个Task,并在该新建的Task上创建Activity。
  • FLAG_ACTIVITY_SINGLE_TOP:这个FLAG就相当于启动模式中的singletop,比如说原来栈中情况是ABCD,在D中启动D,栈中的情况还是ABCD
  • FLAG_ACTIVITY_CLEAR_TOP:这个FLAG就相当于启动模式中的SingleTask,这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。比如:原来栈中的情况是ABCD,这个时候从D中跳转到B,这个时候栈中的情况就是AB了
  • FLAG_ACTIVITY_NO_HISTORY:这个标记顾名思义意思就是说,用这个FLAG启动的Activity,一旦【不可见】,他就不会存在于任务栈中。比如,原来是ABC,这个时候在C中以这个FLAG启动D的 ,D再启动E,这个时候栈中情况为ABCE。
  • FLAG_ACTIVITY_BROUGHT_TO_FRONT:比方说我现在在A中启动B,启动B时在Intent中加上这个标记,此时在B中再正常启动CD,此时栈的情况是ABCD。如果这个时候在D中再启动B,这个时候栈的情况是 ACDB。
  • FLAG_ACTIVITY_REORDER_TO_FRONT:如果在A,B,C,D正常启动的话,不管B有没有用FLAG_ACTIVITY_BROUGHT_TO_FRONT启动,此时在D中启动B的话,还是会变成A,C,D,B的。
  • FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:这个不知道具体怎么用
  • FLAG_ACTIVITY_NO_USER_ACTION:onUserLeaveHint()是activity周期的一部分,它在activity因为用户要跳转到别的activity而使当前activity要退到background时调用。比如,在用户按下Home键(用户的选择)时,它将被调用;但如果是有电话进来(不属于用户的选择,是系统行为),它就不会被调用。那么系统如何区分让当前activity退到background时使用是用户的choice?它是根据促使当前activity退到background的那个新启动的Activity的Intent里是否有FLAG_ACTIVITY_NO_USER_ACTION来确定的。注意:通过调用finish()使该activity销毁时不会调用该函数

taskAffinity属性

清单文件中,activity 的属性android:allowTaskReparenting用于设定:Activity是否能够从启动它的任务栈中【转移到】另一个与启动它的任务栈有相同taskAffinity属性值的任务栈中,转移时机是在另一个任务栈被带到前台的时候。如果设置为true,则能够转移,如果设置了false,则这个Activity必须要保留在启动它的那个任务栈中。

实验

1、新建两个工程,App1和App2

App1和App2都设置android:taskAffinity="aaa.aaa" android:allowTaskReparenting="true"

先运行App1,然后点击home键,让App1运行在后台

再运行App2,会发现这时显示的是App1的mainActivity,并且长按home键,会发现运行过的程序只有App1。

2、紧接着又在此基础上做了另外一个实验

在App1上新建一个secondActivity,设置android:taskAffinity="aaa.bbb" android:allowTaskReparenting="true"

在mainActivity中startActivity时,设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK。

然后运行App1,点击进入secondActivity,这时长按home键,会发现运行过的程序中有两个App1,并且一个显示的是mainActivity另一个显示的是secondActivity。

这时点击home键,让程序回到后台

然后运行App2,会发现这时显示的是App1的mainActivity,此时点击返回会直接返回home。

注意,虽然此时App1的mainActivity被finish了,但App1的secondActivity还在后台等着呢。

同样,长按home键,会发现运行过的程序只有App1的两个任务栈,并没有App2。

3、在此基础上对App1再次修改

在App1上新建一个thirdActivity,设置属性android:taskAffinity="aaa.aaa" android:allowTaskReparenting="true"

并在secondActivity中startActivity时,设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK;

运行App1,点击进入secondActivity,再进入thirdActivity,此时长按home键,会发现运行过的程序中有两个App1,并且一个显示的是secondActivity另一个显示的是thirdActivity。

此时点击返回,会回到mainActivity,再点击返回,会回到secondActivity,再点击返回,回到home页面。

以上实验中,如果startActivity时不设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK,则若先启动的是App1,那么不管是App1中的Activity还是App2中的mainActivity,都是运行App1的一个任务栈中。

任务栈简单了解

我们在开发项目的过程中,一般都需要在本应用中多个Activity组件之间的跳转,也可能需要在本应用中打开其它应用的可复用的Activity。如我们可能需要跳转到原来某个Activity实例,此时我们更希望这个Activity可以被重用而不是创建一个新的 Activity,但根据Android系统的默认行为,确实每次都会为我们创建一个新的Activity并添加到Task中,这样android系统是不是很傻?还有一点就是在我们每开启一次页面加入到任务栈Task中后,一个Activity的数据和信息状态都将会被保留,这样会造成数据冗余, 重复数据太多, 最终还可能导致内存溢出的问题(OOM)。

  • android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。
  • 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
  • 在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。
  • 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。

android系统提供了一套Activity的启动模式来修改系统Activity的默认启动行为。目前启动模式有四种,接下来我们将分别介绍这四种模式。

Standard 模式

又称为标准模式,也是系统的默认模式(可以不指定),在这样模式下,每启动一个Activity都会重新创建一个Activity的新实例,并且将其加入任务栈中,而且完全不会去考虑这个实例是否已存在。

在standard模式下启动三次MainActivity后,都会生成了不同的新实例,并添加到同一个任务栈中。这个时候Activity的onCreate、onStart、onResume方法都会被调用。

singleTop 模式

又称栈顶复用模式,顾名思义,在这种模式下,如果有新的Activity已经存在任务栈的栈顶,那么此Activity就不会被重新创建新实例,而是复用已存在任务栈栈顶的Activity。这里重点是位于栈顶,才会被复用,如果新的Activity的实例已存在但没有位于栈顶,那么新的Activity仍然会被重建。需要注意的是,Activity的onNewIntent方法会被调用。

这种模式通常比较适用于接收到消息后显示的界面,如qq接收到消息后弹出Activity界面,如果一次来10条消息,总不能一次弹10个Activity吧?再比如新闻客户端收到了100个推送,你每次点一下推送他都会进入某个activiy界面(显示新闻只用一个activity,只是内容不同而已),这时也比较适合使用singleTop模式。

singleTask 模式

又称为栈内复用模式。这是一种单例模式,与singTop点类似,只不过singTop是检测栈顶元素是否为需要启动的Activity,而singTask则是检测整个栈中是否存在当前需要启动的Activity,如果存在就直接将该Activity置于栈顶,并将该Activity以上的Activity都从任务栈中移出销毁,同时也会回调onNewIntent方法

singleTask 模式比较适合应用的主界面activity,里面有好多fragment,一般不会被销毁,它可以跳转其它的activity界面再回主架构界面,此时其他Activity就销毁了。当然singTask还有一些比较特殊的场景这个我们后面会一一通过情景代码分析。

singleInstance 模式

在singleInstance模式下,该Activity在整个android系统内存中有且只有一个实例,而且该实例单独尊享一个Task。换句话说,A应用需要启动的 MainActivity 是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A单独在这个新的任务栈中,如果此时B应用也要激活MainActivity,由于栈内复用的特性,则不会重新创建,而是两个应用共享一个Activity的实例。

2019-2-27

任务栈 启动模式 Flag taskAffinity的更多相关文章

  1. 任务栈 启动模式 Task Flag launchMode MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. Activity 启动模式 FLAG

    原文:https://blog.csdn.net/youhongyan/article/details/64151922 一.Activity启动模式的设置在AndroidManifest.xml文件 ...

  3. Android中的TaskStack及启动模式

    目录 前言 如何观察ActivityStack? 几个问题 关键类介绍 ActivityStack的创建与种类 不同启动模式 launchMode Standard SingleTop SingleT ...

  4. 对Activity启动模式的理解

    对Activity启动模式的理解 应用场景 在已打开多个Activity应用B的前提下,应用A调用应用B后点击返回按钮,需要直接返回到A应用,而不是打开B应用的上一个Activity 一个Task可以 ...

  5. Activity的任务栈Task以及启动模式与Intent的Flag详解

    什么是任务栈(Task) 官方文档是这么解释的 任务是指在执行特定作业时与用户交互的一系列 Activity. 这些 Activity 按照各自的打开顺序排列在堆栈(即“返回栈”)中. 其实就是以栈的 ...

  6. Activity启动模式 及 Intent Flags 与 栈 的关联分析

     http://blog.csdn.net/vipzjyno1/article/details/25463457    Android启动模式Flags栈Task   目录(?)[+] 什么是栈 栈 ...

  7. android Activity的启动模式与flag的见解

    最近做一个安卓项目,想要实现的效果就是:当打开一个按钮的时候,启动了一个A功能,当用户返回到桌面再继续进去的时候,不过之前在哪个Activity,都会先跳转到A功能的那个界面,当用户点击返回的时候,再 ...

  8. 【转】Activity启动模式 及 Intent Flags 与 栈 的关联分析

    http://blog.csdn.net/vipzjyno1/article/details/25463457    在学习Android的过程中,Intent是我们最常用Android用于进程内或进 ...

  9. activity的启动模式和栈管理

     在学习Android的过程中,Intent是我们最常用Android用于进程内或进程间通信的机制,其底层的通信是以Binder机制实现的,在物理层则是通过共享内存的方式实现的.     Intent ...

随机推荐

  1. libthrift0.9.0解析(三)之TProtocol&TTransport

       以上是transport和protocol的类图和结构图. transport封装了底层的传输通道,主要有read/write.open/close等基本的读写方法,而且都是对于二进制数据. p ...

  2. Qt5-控件-QMenu,QMenuBar-菜单栏详解-菜单热键-菜单校验功能

    #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QMenu> #inclu ...

  3. linux 防火墙--firewalld学习

    firewalld是centos7默认的防火墙,相比于iptables重要的优势: 1 支持动态更新: 2 不用重启服务: 同时增加了防火墙的“zone”概念,具体差异没做过多了解,这篇文章只记录fi ...

  4. C++ Primer 5th 第9章 顺序容器

    练习9.1:对于下面的程序任务,vector.deque和list哪种容器最为适合?解释你的选择的理由.如果没有哪一种容器优于其他容器,也请解释理由.(a) 读取固定数量的单词,将它们按字典序插入到容 ...

  5. GET——token

    private function get_token(){ $appid="wx4dae5d61b7f9935c"; $appSecret="24a91315a1a62a ...

  6. .NET MVC插件化开发(支持Script和css压缩)

    上一篇博文里面,没有支持Script和css的压缩功能以及script和css的路径问题也没有解决,所以重新发布一个版本,解决了这几个问题,并且优化了插件路由注册,现在可以很方便的实现热插拔web插件 ...

  7. Linux_install jdk

    Linux安装JDK步骤 1.先从网上下载jdk(jdk-7u1-linux-i586.rpm),下载地址:http://www.oracle.com/technetwork/java/javase/ ...

  8. 大小写转换,split分割

    一.大小写转换 1.定义和用法 toUpperCase() 方法用于把字符串转换为大写. toLowerCase() 方法用于把字符串转换为小写.    用法: stringObject.toUppe ...

  9. Swift—Cocoa Touch设计模式-备

    目标(Target)与动作(Action)是iOS和OS X应用开发的中事件处理机制.   问题提出 如图所示是一个ButtonLabelSample案例设计原型图,其中包含一个标签和一个按钮,当点击 ...

  10. 递归目录的shell脚本

    #! /bin/sh # 在其他目录运行时一定要加上这样的语句 # 尤其是配置在crontab里自动运行 cd `` #定义数据别名 alias statdb="/usr/local/mys ...