launchMode,通俗点说,就是定义了Activity应该如何被launch的。那么这几种模式的区别以及应用场景,会有何不同呢?谷歌是基于什么原因设计这几种模式的呢?这几种模式背后的工作原理是什么呢?

1. 任务和返回栈

在讲解launchMode之前,先说说任务(Task)和返回栈(Back Stack,有些译作回退栈、任务栈)这两个概念。

A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack—the back stack—in the order in which each activity is opened.

任务是指当完成一个特定的工作时与用户交互的一系列Activity。这些Activity按照打开的顺序存放在一个栈中,即返回栈。

通过定义可以知道,Activity会被按照打开的顺序存放。不难猜想,这种存放方式,是为了方便回退操作,也就不难解释为什么要用栈去存放。

当用户点击启动app的时候,这个app的返回栈就会跑到前台,如果这个返回栈不存在的话,就会创建一个。当前Activity启动另一个Activity的时候,新的Activity就会入栈,在栈顶。如果用户点击返回按钮,当前的Activity就会出栈并销毁,之前的Activity就会被resume,如果栈为空,就会被销毁掉。栈中的Activity永远都不会被重新排序。

返回栈根据是否在前台,可以分为在前台显示的返回栈,和置于后台的返回栈。其中,置于后台的返回栈中所有的Activity都处于stop状态,用户可以手动的去切换前后台的返回栈状态。

当系统内存不足时,系统会优先销毁处于后台的Activity。那么问题来了。后台销毁Activity的优先级是怎样的呢?是将一个返回栈中的Activity都销毁了过后,再去销毁另一个,还是说,只是单纯的按照Activity来销毁回收呢?

1.1 任务管理

任务以及返回栈的管理,可以通过一系列的参数设置来进行,包括我们本文讲解的launchMode,也是任务管理的一种方式。

1.1.1 taskAffinity

TaskAffinity即任务相关性,标识一个Activity所需要的返回栈的名字。默认情况下是包名。设置了相同taskAffinity属性的Activity会被放进同一个栈中。一个返回栈的相关性(affinity)是由这个栈的根Activity的相关性(affinity)决定的。

taskAffinity属性主要与singleTask或allowTaskReparenting结合使用,在其他情况下,这个属性没有作用。这是为什么呢?

1.1.2 allowTaskReparenting

它的主要作用是Activity的迁移,从一个栈迁移到另一个栈,这个迁移跟Activity的taskAffinity有关。

1.1.3 clearTaskOnLaunch

这个属性用来清除回退栈中除了根Activity的所有Activity,只对根Activity起作用。当设置为true时,每次重新进入app,只会看到根Activity。

1.1.4 finishOnTaskLaunch

这个属性与clearTaskOnLaunch相反,它是将本Activity移除出去,而不影响其他的Activity。

1.1.5 alwaysRetainTaskState

这个属性的作用是保存返回栈的状态,只对根Activity起作用。正常情况下,系统清理一个返回栈,会将根Activity之上的所有Activity都清除掉。设置该属性后,系统会保存当前的状态。

2. 启动模式

启动模式主要的作用是什么呢?根据上面对任务及返回栈的介绍,它的作用是定义,一个新的Activity实例如何与当前的任务相关联。它本身是任务的管理方式。

启动模式有两种定义方式,manifest里定义和intent flag的方式。一种是类似配置式的,一种是代码层面的。可以大致推测,肯定是带么层面的优先级高一些,但是代码方式劣处就是不启动Activity就无法设置。Android中这种一般提供动态以及静态方式的,套路都大致相同,一些区别各种优劣等。

其中manifest设置与intent flag中都包含对方没有的方式。这也是两者的一个区别。

2.1 launchMode

此处的launchMode专指Activity的launchMode属性。其中有四种方式,这四种方式想必大家也都很清楚了,在这里我不详细展开了。

2.1.1 standard

最常见的一种模式,Activity的默认模式,每次启动该模式的Activity,都会被重新创建,可以从属不同的任务,也可以在一个任务中被创建多次。

它的应用场景特别广泛, 一般不是特殊需求的话,都会去使用这种模式。

2.1.2 singleTop

如果在当前任务的栈顶,系统会调用Activity的onNewIntent()方法而不是重新创建一个新的实例。当用户点击返回键时,当前Activity会被出栈,而不是会退到onNewIntent()之前的状态。

它的应用场景也有一些。例如搜索页面,每次打开,搜索一些结果,点击详情页面,然后继续搜索。在比方说,通过通知打开的页面,如果该页面存在,则更新,如果不存在,则创建。

2.1.3 singleTask

该模式只允许系统中存在一个该Activity的实例,如果当前实例不存在,则创建,如果已经存在,则将该实例之上的Activity全部出栈,走onNewIntent()。

singleTask适合作为程序入口点,当通过其他方式调用app时候,不会反复创建主页面。例如一般情况下的MainActivity,其他app调用的时候。

2.1.4 singleInstance

这种模式与singleTask十分类似,区别在于,持有该Activity的任务中只能包含一个Activity即它本身。

singleInstance适合需要与程序分离开的页面,例如闹钟的响铃界面,与闹钟的设置相分离。再例如系统的拨号界面。

2.2 Intent flags

此处讨论的是通过代码方式进行设置,常见的有如下三种方式。

2.2.1 FLAG_ACTIVITY_NEW_TASK

使用一个新的返回栈来启动Activity,跟上面讨论的singleTask类似

2.2.2 FLAG_ACTIVITY_SINGLE_TOP

跟上面讨论的singleTop类似

2.2.3 FLAG_ACTIVITY_CLEAR_TOP

这种方式是上面讨论的launchMode中不存在的,它与singleTop的区别是,当已存在该实例了,会将它之上的Activity都出栈。

它经常与FLAG_ACTIVITY_NEW_TASK组合使用,可以达到singleTask的作用。

3. 回到问题

几种模式的区别以及应用场景,会有何不同呢?

答案见上面关于launchMode

谷歌是基于什么原因设计这几种模式的呢?

关于这个问题,我们先倒着来推理,即从使用场景去考虑,一般状况下,我们打开一个页面,不在意是否是唯一,这个是最常见的需求,因此有了standard模式,这种也是默认的模式。当我们用搜索页面,当最顶层是搜索页面的时候,我不希望再打开一个搜索页面,于是有了singleTop模式。当从其他App调用我们的app的时候,我只希望只显示一个主页面时,于是有了singleTask。关于singleInstance模式,则是希望与当前的页面分离。

但是,我觉得谷歌并不能列举出所有的场景,例如,我希望打开一个页面,记录当前的路径,例如a->b->c,这种场景下,四种模式里面没有包含。

如果从正面去推导的话,几种启动模式是任务及返回栈的管理。根据在栈中的状态,大致可以分为如下几类:

  1. 最常见的出栈入栈(standard)
  2. 当前栈中唯一(singleTask)
  3. 全局唯一(singleInstance)
  4. 栈顶唯一(singleTop)

是不是很明晰了,有没有其他的出现形式?肯定有的,例如栈底唯一,栈中唯一。但是这种方式可以等同于当前栈中唯一啊。

我们是否可以推导出,谷歌是根据唯一性,来将启动模式分为这几种呢?intent flags则作为辅助的一些操作,例如部分出栈等等。当然这些也只是我的推测,不一定准确,哈哈。

这几种模式背后的工作原理是什么呢?

见任务及返回栈

内存回收的方式,是以Activity还是以任务作为基准回收?

目前已知的状况时,如果返回栈置于后台,当内存不足的时候,如果不设置alwaysRetainTaskState属性的话,会将除了根Activity的所有Activity销毁掉。可以确定是以返回栈为基准来进行回收。

taskAffinity属性为什么与singleTask一起使用才生效?

可以将Activity的launchMode根据是否在栈中唯一分为两类

  1. standard、singleTop
  2. singleTask、singleInstance

第一类因为其唯一性,肯定是与taskAffinity不兼容的。singleInstance创建的栈中只能包含本身,默认情况下都会单独创建一个栈,指定与否都会单独创建,因此设置没有意义。而singleTask则是当前栈中唯一,适合作为根Activity,创建一个新的栈,这也是为什么taskAffinity只能对根Activity起作用的缘故。

4. 最后

我写的内容不一定正确,一些问题的解释也是根据我看到的资料来推到出来的,例如Activity为什么会有四种启动模式,如果大家有准确地答案,希望告知。另外,文中错误的地方,也希望指正。

最后,感谢大家的浏览,希望对您有所帮助。

喜闻乐见-Android LaunchMode的更多相关文章

  1. android launchmode(四种启动模式)应用场景及实例

    模式介绍 [1] standard 模式 这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中. [2] singleTop 模式 如果在任务的栈顶正好存在该Activ ...

  2. android:launchMode的四种方式

    Activity一共有以下四种launchMode: standard singleTop singleTask singleInstance 1.standard standard模式是默认的启动模 ...

  3. android:launchMode概述

    android:launchMode An instruction on how the activity should be launched. There are four modes that ...

  4. android:launchMode="singleTask" 与 onNewIntent(Intent intent) 的用法

    最近项目开发中用到了android:launchMode="singleTask" 和 onNewIntent(Intent intent)两个特性,现总结一下经验: androi ...

  5. Android LaunchMode案例篇

    首先感谢小伙伴的关注.然后祝愿广大的情侣们节日快乐! 在开发中有时会遇到这种场景,用户点击注冊.第一步,第二步,完毕注冊跳转到登录界面,不须要用户一步一步的返回到登录界面.这是怎么实现的呢? 案例:有 ...

  6. Android之android:launchMode

    (本文转自:http://www.eoeandroid.com/blog-531377-3446.html) (详细查看:http://blog.csdn.net/liuhe688/article/d ...

  7. Activity的启动模式(android:launchMode)

    在android里,有4种activity的启动模式,分别为: “standard” (默认) “singleTop” “singleTask” “singleInstance” 它们主要有如下不同: ...

  8. android launchmode singleinstance问题

    问题描述 最近测试关于launchmode的四种方式 默认模式 top singletask 都已经了解了 唯独这个instance模式 我的问题是 我们只作2个activity的假设A和B,其中A为 ...

  9. 喜闻乐见-Android应用的生命周期

    本文主要讲述了App的启动流程.Application的生命周期以及进程的回收机制. 在绝大多数情况下,每一个Android应用都在自己的Linux进程中运行.当需要运行某些代码时,进程就会被创建.进 ...

随机推荐

  1. spring boot -表单校验步骤 +@NotEmpty,@NotNull和@NotBlank的区别

    1.实体类属性上添加注解规则 如 public class User { @NotBlank private Integer id ; 2.在方法中添加注解@Valid和一个校验结果参数(Bindin ...

  2. [原创]k8exe2bat任意文件转Bat工具(WebShell无法上传EXE解决方案)

    http://qqhack8.blog.163.com/blog/static/114147985201126105626755/ 这是我2011年的东西了,当时用此方法可免杀很多马,至今依然有很大的 ...

  3. H5 notification浏览器桌面通知

    Notification是HTML5新增的API,用于向用户配置和显示桌面通知.上次在别的网站上看到别人的通知弹窗,好奇之余也想知道如何实现的.实际去查一下发现并不复杂,且可以说比较简单,故写篇博客分 ...

  4. 利用vi编辑器创建和编辑正文文件(一)

    1.       vim是vi的升级版本. 2.       vi所UNIX和Linux系统内嵌的标准文编辑器,可执行,修改,复制,移动,粘贴和删除正文等命令,也可以进行移动光标,搜索字符和退出vi的 ...

  5. Ajax,JSONP以及跨域问题

    没用过裸的Ajax 也没听过jsonp,也不了解跨域问题,emmm… 参考: http://www.runoob.com/ajax/ajax-tutorial.html https://www.lia ...

  6. Java单元测试(Junit+Mock+代码覆盖率)

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

  7. k8s~术语解释

    文章参考:https://www.kubernetes.org.cn 简介 Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简 ...

  8. 使用google wire解决依赖注入

    使用google wire解决依赖注入 google wire是golang的一个依赖注入解决的工具,这个工具能够自动生成类的依赖关系. 当我们写代码的时候,都希望,类都是一个个独立的结构,互不耦合, ...

  9. Python数据可视化的四种简易方法

    摘要: 本文讲述了热图.二维密度图.蜘蛛图.树形图这四种Python数据可视化方法. 数据可视化是任何数据科学或机器学习项目的一个重要组成部分.人们常常会从探索数据分析(EDA)开始,来深入了解数据, ...

  10. Deploying Keras model on Tensorflow Serving--

    keras训练了个二分类的模型.需求是把keras模型跑到 tensorflow serving上 (TensorFlow Serving 系统用于在生产环境中运行模型) keras模型转 tenso ...