提前致谢:感谢广大互联网大佬记录知识借鉴。

一、Activity的4种启动模式:

1、android:launchMode=”standard” 标准启动模式。这种启动模式也是Activity默认的,一个栈中可以有多个相同的Activity。不会考虑是否栈中是否有相同的Activity。比如设置A为standard模式,那么可以运行A-B-A-A-A;

2、android:launchMode=”singleTop” 单一栈顶启动模式, 又叫栈顶复用模式,栈顶只能存在一个相同的Activity。比如你栈顶是MainActivity.java,你想启动新的MainACtivity.java是无法实现的。但是栈中可以存在多个MainActivity.java实例。 比如设置A为singleTop模式,运行 A-B-A 这里栈中可以同时存在了两个A,但是如果A已经在栈顶了就不能在A之上再启动一个A,这时候虽然系统不会调用A的onCreate(),但会调用onNewIntent(),即位于栈顶的activity被复用。

当一个Activity已经在栈顶,但依然有可能启动它,而你又不想产生新的Activity实例,此时就可以用singleTop模式。

3、android:launchMode=”singleTask” 单一栈启动模式,又叫栈内复用模式,当使用这种启动模式的时候,栈中只能存在一个相同Activity的实例。比如设置A为singleTask模式,那么执行 A-B-C-D ,此时D在栈顶,你想启动一个A,此时会直接启动在栈底层的A,而不会去新建一个A,并且此时A已经成为了栈顶了,所以B-C和D都是被移出栈,也就是被销毁了,同理系统不会调用A的onCreate(),但会调用onNewIntent(),即栈内的activity被复用。

singleTask模式和前面两种模式的最大区别就是singleTask模式是任务内单例的,所以我们是否设定Activity为singleTask模式,就是看我们activity是否需要单例,例如你的某个Activity里面有一个列表,如果有多个实例,有可能导致用户看到的列表不一致,有的Activity需要经常启动,如果每次都创建实例,会导致占用资源过多,这些情况都可以使用singleTask模式(例如Launcher应用的activity就是singleTask模式的),但启动singleTask模式的Activity会导致任务栈内它上面的Activity被销毁,有可能会影响用户体验,使用时要注意。

4、android:launchMode=”singleInstance” 单例启动模式,singleInstance模式也是单例的,但和singleTask不同,singleTask只是任务栈内单例,系统里是可以有多个singleTask Activity实例的,而singleInstance Activity在整个系统里只有一个实例,启动一singleInstanceActivity时,系统会创建一个新的任务栈,并且这个任务栈只有他一个Activity。比如设置B为这种模式, 那么当依次启动A-B-C-D(此时D在栈顶),此时原始的栈中就有A、C、D这三个Activity,而B在一个新的栈中。此时当你按back键,你会发现是这样子的,D-C-A–B,这是因为DCA在先创建的(也就是主栈)中,所以当主栈中的Activity全部都移除栈外后, 才会轮到次栈,这个次栈中只有一个B。

把Activity独立于一个栈中,是为了别的程序访问此Activity,可以方便多个应用程序共享这个栈中的Activity。SingleInstance模式并不常用,如果我们把一个Activity设置为singleInstance模式,你会发现它启动时会慢一些,切换效果不好,影响用户体验。它往往用于多个应用之间,例如一个电视launcher里的Activity,通过遥控器某个键在任何情况可以启动,这个Activity就可以设置为singleInstance模式,当在某应用中按键启动这个Activity,处理完后按返回键,就会回到之前启动它的应用,不影响用户体验。

二、几种常见的启动Activity的FLAG

(1) FLAG_ACTIVITY_NEW_TASK

设置此状态,记住以下原则,首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即taskAffinity,注意同一个应用程序中的activity的亲和性一样,所以下面的a情况会在同一个栈中),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity。

a. 前提: Activity A和Activity B在同一个应用中. 
 
操作: Activity A启动时开僻Task堆栈(堆栈状态: A), 在Activity A中启动Activity B, 启动Activity B的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK, Activity B被压入Activity A所在堆栈(堆栈状态: A-B).

原因: 默认情况下同一个应用中的所有Activity拥有相同的关系(taskAffinity).

b. 前提: Activity A在名称为"TaskOne应用"的应用中, 
        Activity C和Activity D在名称为"TaskTwo应用"的应用中.

操作1: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),在Activity A中启动Activity C, 启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK,Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 长按任务键, 然后选择TaskA, Activity A回到前台, 再次启动Activity C(两种情况1.从桌面启动;2.从Activity A启动,两种情况一样), 这时TaskB回到前台, Activity C显示, 供用户使用, 即:包含FLAG_ACTIVITY_NEW_TASK的Intent启动Activity的Task正在运行, 则不会为该Activity创建新的Task,而是将原有的Task返回到前台显示.

操作2: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A), 在Activity A中启动Activity C,启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK, Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 在Activity C中启动Activity D(TaskB的状态: CD) 长按Home键, 选择TaskA, Activity A回到前台, 再次启动Activity C(从桌面或者ActivityA启动,也是一样的),这时TaskB回到前台, Activity D显示,供用户使用.说明了在此种情况下设置FLAG_ACTIVITY_NEW_TASK后,会先查找是不是有Activity C存在的栈,根据亲和性(taskAffinity),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的顺序不变

(2) FLAG_ACTIVITY_CLEAR_TOP:

从字面意思上看是要将栈中所启动activity之上的所有activity清除,通过此flag启动时还是按照默认在本栈上启动,清除上面的activity,但是即使所启动的activity已存在,仍会销毁重新创建,如果结合single top 的flag则不会重新创建。

前提: Activity A, Activity B, Activity C和Activity D在同一个应用中.

操作: Activity A启动开僻Task堆栈(堆栈状态: A), 在Activity A中启动Activity B(堆栈状态: AB), 在Activity B中启动Activity C(堆栈状态: ABC), 在Activity C中启动Activity D(堆栈状态: ABCD), 在Activity D中启动Activity B,启动Activity B的Intent的Flag设置为FLAG_ACTIVITY_CLEAR_TOP, (堆栈状态: AB).

(3) FLAG_ACTIVITY_CLEAR_TASK:

必须配合new task使用,表示新启动的activity作为新栈的根activity。

(4) FLAG_ACTIVITY_BROUGHT_TO_FRONT:

前提: Activity A在名称为"TaskOne应用"的应用中, Activity C和Activity D在名称为"TaskTwo应用"的应用中.

 操作: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A), 在Activity A中启动Activity C,启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK, Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 在Activity C中启动Activity D(TaskB的堆栈状态: CD), 长按Home键, 选择TaskA, Activity A回到前台, 在Activity A中再次启动Activity C, 在启动Activity C的Intent中设置Flag为FLAG_ACTIVITY_BROUGHT_TO_FRONT, TaskB回到前台, Activity C显示, (TaskB的堆栈状态: C).

(5) FLAG_ACTIVITY_MULTIPLE_TASK:

与FLAG_ACTIVITY_NEW_TASK结合使用, 首先在Intent中设置FLAG_ACTIVITY_NEW_TASK, 打开Activity,则启动一个新Task, 接着在Intent中设置FLAG_ACTIVITY_MULTIPLE_TASK, 再次打开同一个Activity,则还会新启动一个Task.

(6) FLAG_ACTIVITY_SINGLE_TOP:

当前Task堆栈中存在ABCD四个Activity, A是栈顶Activity, D为栈底Activity, 存在打开A的Inten中设置了FLAG_ACTIVITY_SINGLE_TOP标志, 则会使用栈顶A, 而不会从新New A.

(7) FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:

一般与FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET结合使用,如果设置该属性,这个activity将在一个新的task中启动或者或者被带到一个已经存在的task的顶部,这时这个activity将会作为这个task的首个页面加载。将会导致与这个应用具有相同亲和力的task处于一个合适的状态(移动activity到这个task或者从中移出),或者简单的重置这个task到它的初始状态

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET:在当前的Task堆栈中设置一个还原点,当带有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent请求启动这个堆栈时(典型的例子是用户从桌面再次启动这个应用),还原点之上包括这个应用将会被清除。应用场景:在email程序中预览图片时,会启动图片观览的actvity,当用户离开email处理其他事情,然后下次再次从home进入email时,我们呈现给用户的应该是上次email的会话,而不是图片观览,这样才不会给用户造成困惑。

例: 存在Activity A, Activity B, Activity C, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A), 在Activity A中启动Activity B(TaskA堆栈状态: AB), 接着Activity B启动Activity C(TaskA堆栈状态: ABC), 启动Activity C的Intent中设置FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET标题, 这样TaskA中有一个还原点, 当有包含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent请求TaskA堆栈时(比如请求Activity A)系统就会将还原点以上的Activity清除, TaskA堆栈中只剩下了AB.

三、taskAffinity属性:

(1) taskAffinity属性应和FLAG_ACTIVITY_NEW_TASK标志及allowTaskReparenting属性结合使用, 如果只使用taskAffinity属性,请参考上面Task默认的行为.

(2) 与FLAG_ACTIVITY_NEW_TASK标志结合:

a. 前题: Activity A和Activity B在同一个应用中, Activity A与Activity B设置不同的taskAffinity属性.

操作: Activity A启动开僻Task堆栈,命名为TaskA(TaskA堆栈状态: A), 在Activity A中启动Activity B, 启动Activity B的Intent中设置FLAG_ACTIVITY_NEW_TASK标志,这时系统会新开僻一个Task堆栈,TaskB(TaskB堆栈状态: B).

b. 前题: Activity A,Activity C在同一个应用中, Activity A和ActivityC设置了相同的taskAffinity属性.

操作: Activity A启动开僻Task堆栈,命名为TaskA(TaskA堆栈状态: A), 在Activity A中启动Activity C, 启动Activity C的Intent中设置FLAG_ACTIVITY_NEW_TASK标志,这时Activity C会压入与Activity A堆栈相同的TaskA堆栈(TaskA堆栈状态: AC).

(3) 与allowTaskReparenting属性:

例: 在"TaskOne应用"中有一个天气预报Activity A, Activity A与"TaskOne应用"中的其它Activity有默认的关系(taskAffinity属性都没有设置), 并且allowTaskReparenting属性设置为true, 现在存在一个"TaskTwo应用"启动了"TaskOne应用"中的天气预报Activity A,  这时Activity A与"TaskTwo应用"中的Activity在同一个Task,命名这个Task堆栈为TaskA, 这时"TaskOne应用"启动, 并且又打开发天气预报Activity A, 这时Activity A会从TaskA堆栈中转移到"TaskOne应用"所在的堆栈, 即Activity A可以在多个堆栈中来回转移.

四、 alwaysRetainTaskState属性:

如果Task堆栈中的Root Activity设置了此属性值为true, 不管出现任何情况, 一直会保留Task栈中Activity的状态.

五、 clearTaskOnLaunch属性:

如果Task堆栈中的Root Activity设置了此属性值为true, 只要你一离开这个Task栈, 则系统会马上清理除了Root Activity的全部Activity.

六、 finishOnTaskLaunch属性:

如果某Activity设置了finishOnTaskLaunch属性, 只要你一离开这个Task栈, 则系统会马上清除这个Activity,不管这个Activity在堆栈的任何位置.

七、startActivityForResult相关的一些坑

正因为activity的很多启动模式或flag具有清除栈内已有activity的效果,清除实际是调用的系统的remove task方法,该方法会使得被清除的activity 执行onDestory等方法销毁,同时如果被销毁的activity是被其他activity 用startActivityForResult方法启动的,销毁时会给它的启动activity传递回去result cancel 事件,启动activity 的onActivityResult方法会被调用,这个时候容易出现我们意料之外的问题。

例如:A是一个桌面应用的入口 activity,并设为了singleTask 启动模式的,我在A中用startActivityForResult方法启动了B,其中有个逻辑是如果在A的的onActivityResult方法中回调了 Result cancel事件——A activity调用finish销毁。首次点击A,然后在A中用startActivityForResult启动B,这里没问题,然后home键回桌面,再次点击应用图标启动,此时发现没有反应什么界面都没出现,看现象还以为应用异常闪退。实际是由于A是singleTask 启动模式,点图标启动A时要清除A所在栈上面的所有activity,栈中B被remove task 然后onDestory, 栈中原来的A收到onActivityResult事件,然后执行finish也销毁了,然后就因为没有activity存在了不显示任何界面。

从Task的角度看,Android认为不同Task之间的Activity是不能传递数据的,因此如果启动用startActivityForResult方式启动新activity,而新启动的activity和当前activity不在同一个栈时,当前activity的onActivityResult方法回马上被回调,并且传递回result cancel事件,可以从AMS打出的log上看到有这么一句:
“WARN/ActivityManager(67): Activity is launching as a new task, so cancelling activity result.” 就是这个意思,下面startActivityForResult的注释也进行了说明。

因此对于启动模式是singleInstance或singleTask,或者是new task flag标志启动的情况要尤其注意下此问题。

Activity 启动模式以及常见的启动Flag相关推荐

  1. 【Android 应用开发】Android 返回堆栈管理 ( 默认启动模式 | 栈顶复用启动模式 | 栈内复用启动模式 | 单实例启动模式 | CLEAR_TOP 标识 )

    文章目录 I . 默认启动模式 ( standard ) II . 栈顶复用启动模式 ( singleTop ) III . 栈内复用启动模式 ( singleTask ) IV . 单实例启动模式 ...

  2. android 怎么自定义任务栈,Android中的Activity详解--启动模式与任务栈

    目录 Activity 生命周期 任务栈 启动模式 Intent Flag taskAffinity属性 1.Activity activity的简单介绍就不写了,作为最常用的四大组件之一,肯定都很熟 ...

  3. 【Android 12】Activity启动模式

    本文结合demo App和手机的实际情况(dumpsys activity containers),分析一下Activity的启动模式. 一.启动模式 google文档的介绍: 您可以通过启动模式定义 ...

  4. Activity的启动模式

    题目:Activity的启动模式,区别 这道题想考察什么? 启动模式是什么? 启动模式如何设置? Activity的启动模式区别? 应用场景以及那些注意的点? 考察的知识点 启动任务,返回栈,启动模式 ...

  5. Android入门:Activity四种启动模式

    2019独角兽企业重金招聘Python工程师标准>>> 一.启动模式介绍 启动模式简单地说就是Activity启动时的策略,在Android Manifest.xml中的标签的and ...

  6. 【Android 应用开发】Activity 返回堆栈管理 ( 阶段总结 | 任务栈管理 | 返回堆栈 | 清除返回堆栈 | 亲和性 | 启动模式补充 | standard | singleTop )

    文章目录 一. 安卓应用任务栈管理 二. 任务与返回堆栈回顾 三. 返回堆栈清除 四. 关于亲和性回顾 五. Activity 启动模式 LaunchMode 补充 ( standard | sing ...

  7. Android初级开发笔记-- activity启动模式的学习(1)

    第一次学习Android中一个很重要的概念,启动模式.文章记录的也只是一些入门知识,随着学习的深入还会有activity启动模式的学习(2)和(3). 下面分三个小点说一下对启动模式的理解区别以及如何 ...

  8. android的四种启动模式,(转)彻底弄懂Activity四大启动模式

    原地址:https://blog..net/mynameishuangshuai/article/details/51491074 最近有几位朋友给我留言,让我谈一下对Activity启动模式的理解. ...

  9. 安卓学习笔记06:Activity生命周期与启动模式

    文章目录 零.学习目标 一.Activity生命周期 1.了解Activity生命周期 2.Activity生命周期简化图 (1)Activity存在与否 (2)Activity可见与否 (3)Act ...

最新文章

  1. Xamarin.Forms探索--使用 Xamarin.Forms 来创建跨平台的用户界面
  2. 从零开始搭建物联网平台(6):消息的持久化
  3. ssm项目之maven添加pom jar包配置
  4. es6删除数组某一项_精学手撕系列——数组扁平化
  5. python爬取新闻网站标题_python如何正确抓取网页标题
  6. python爬虫外快_我用Python爬虫挣钱的那些事
  7. 必须知道的ADO.NET 数据库连接池
  8. On the other hand, regarding Linux Mint’s
  9. 发布一个基于 Reactor 模式的 C++ 网络库
  10. C#调用c++Dll结构体数组指针的问题
  11. 电子设计从零开始(第2版)pdf
  12. 历届美国梦之队战斗力汇总:梦一无敌 梦十二平淡
  13. 【论文阅读】2018-基于深度学习的网络流量分类及异常检测方法研究_王伟
  14. 一个线性四叉树编码的试题
  15. 如何设计可靠的灰度方案
  16. 奥比3d 摄像头 android,Android系统下如何允许奥比中光3D传感摄像头USB设备访问
  17. php上传文件产生的临时文件问题,以及所谓的资源类型到底是什么
  18. 数字变成大写的类,把人民币转化为大写汉字
  19. RANSAC算法实现图像全景拼接
  20. loadrunner入门教程(24) --Load Generator

热门文章

  1. svd协同过滤java实现_利用 SVD 实现协同过滤推荐算法
  2. 如何将response里header的date转化为当地时间_外贸独立站卖家如何选择收款方式?...
  3. 本质矩阵与基本矩阵(对极几何)
  4. mysql 错误1930xc1_Mysql写入记录出现 Incorrect string value: '\xB4\xE7\xB1\xCA\xBC\xC7‘错误?(写入中文)...
  5. 以太坊白皮书_区块链60讲第33集~什么是以太坊?
  6. 二十五:设计模式的总结
  7. Nginx-场景实践篇
  8. ASP.NET2.0中的全球化与本地化UICulture,Culture
  9. JSP 中的Cookie
  10. 利用802.11x协议实现动态vlan的划分