前言

本文主要涉及android系统对于activity的组织管理。activity是死的,只有在系统的调度下,才在手机上呈现各种各样的界面,而有那么多的activity,系统是以什么样的规则去管理调度则是一个值得深入探究的问题。

首先介绍几个概念:

  • 什么是Task?

    task翻译过来就是任务,好比用户在使用不同的app是在做不同的任务,而一个app一般有多个activity,所以有必要根据不同的任务来进行activity的管理。
  • 什么是Stack?

    学过数据结构都知道Stack是一种先进后出的数据结构,用stack来管理activity是理所当然的。当切换到一个新的界面时,该activity被push到栈顶,当移除时新的栈顶则变成前一个activity。
  • 什么是ActivityStack?Android使用ActivityStack来管理task,一个ActivityStack由不同的任务组成;

如何观察ActivityStack?

可以通过adb shell dumpsys activity activities观察ActivityStack等活动状态,这儿可以看到实际的组织如前面所说,ActivityStack包含Task,而Task包含Activity;如果对应到AMS中的数据结构,那么就是ActivityStack、TaskRecord、ActivityRecord,下面将从代码层面讲述这几个关键类。

几个问题

  • 同一个应用的Activity一定在同一个task里吗?
  • 返回和startActivity一样吗?
  • 普通任务栈与Stack #0无关,为什么返回到最后退到了launcher?
  • android:launchMode和intent.flag有什么区别与联系?
  • 既然每一个taskrecord都有栈顶的ActivityRecord,那到底哪个task才是在前台的?
  • 各种模式最佳应用场景?为什么要区分这四种启动模式?
  • TaskAffinity是什么?对哪些模式有影响?

关键类介绍

Ams中关于Activity管理的几个关键类关系如下所示

  • ActivityStackSupervisor

在AMS构造的时候就会创建,全局唯一;管理所有的ActivityStack,同时在启动一个Activity的流程中也有重要作用,这个之后分析。

  • ActivityStack

    管理任务栈。有多个,其中一开机就会有Stack #0,Launcher所在的Stack
  • TaskRecord 记录任务,管理Activity
  • ActivityRecord 一个Activity实例在Ams中的记录,同一个Activity类可能有多个记录存在

ActivityStack的创建与种类

./frameworks/base/core/java/android/app/ActivityManager.java

        /** Invalid stack ID. */
public static final int INVALID_STACK_ID = -1; /** First static stack ID. */
public static final int FIRST_STATIC_STACK_ID = 0; /** Home activity stack ID. */
public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID; /** ID of stack where fullscreen activities are normally launched into. */
public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; /** ID of stack where freeform/resized activities are normally launched into. */
public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1; /** ID of stack that occupies a dedicated region of the screen. */
public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1; /** ID of stack that always on top (always visible) when it exist. */
public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1; /** Last static stack stack ID. */
public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID; /** Start of ID range used by stacks that are created dynamically. */

最常用的是HOME_STACK_ID即Stack #0和一般Stack #1。每次开机的时候即会创建Stack #0,这是launcher和systemui的RecentsActivity所在的Stack;当从launcher点击一个图标进入新的app后,则会创建stack #1以及相应的taskrecord

不同启动模式

不同的启动模式主要涉及到ActivityRecord的管理。Android并没有简单地对Activity进行栈式的“先入后出”管理,因为实际的使用各个应用间的Activity组件可以相互调用,同时根据实际的需求又衍生出了各种启动模式。有了上面背景知识的铺垫,可以更好的理解各种launchMode和Intent的flag具体含义。

launchMode

Standard

这也是默认模式,含义是每次startActivity时都会创建一个新的实例,并且走完onCreate、onStart和onResume 。值得注意的是两点:

  1. 该ActivityRecord会放在启动它的Activity所在的任务栈的栈顶。
  2. 可以在同一个任务栈出现多个实例
  3. 如果在没有任务栈的情况下启动 standard 模式的 Activity,比如在 Service 中,此时新的 Activity 没有任务栈可入,会出现异常:
Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

此时应该为这个 Activity 指定 FLAG_ACTIVITY_NEW_TASK,这样就会新建一个任务栈。

SingleTop

顾名思义,SingleTop的含义是在栈顶只存在一个同样的Activity实例,即当startActivity自身的时候,如果该Activity已经存在在栈顶,那么并不重新创建一个实例,而是调用其onNewIntent回调。注意这仅是SingleTop,是允许栈中间存在相同实例的。

前面两种情况其实都是针对同一个任务栈来说的,并且要么是该任务栈不存在需要创建,要么就是前一个Activity所在的任务栈。接下来将说一下可能涉及到不同任务栈的情况

SingleTask

SingleTask是一种栈内复用模式,比前面两种复杂一些。首先寻找需要的任务栈,需要的含义是通过TaskAffinity指定的任务栈名字,默认就是包名。如果不存在,则创建相应的任务栈并将Activity放入栈顶;如果存在需要的任务栈,再看是不是位于栈顶,如果位于栈顶则只需要调用onNewIntent,如果不位于栈顶则pop出在此Activity之上的活动,让此Activity到栈顶。所以SingleTask可能会影响到其他Activity的生命周期。

SingleInstance

在一个新栈中放入该Activity,并且这个栈只能存放这一个Activity;一旦SingleInstance模式的Activity已经存在,则会一直复用这个Activity实例。

回顾问题

我们在前言中提到了几个问题,现在再回过头来看一下。

  • 同一个应用的Activity一定在同一个task里吗?
显然不是。一个Activity组件可以存在于调用者的任务栈中,也可以通过TaskAffinity去设置需要的任务栈,也可以设置SingleInstance单独存在。
  • 返回和startActivity的区别?
onBackPressed最终调用了finish,是会将当前Activity从栈顶移除的;而startActivity则根据启动模式的设置,依照规则去操作任务栈。
  • 普通任务栈与Stack #0无关,为什么返回到最后退到了launcher?
  • android:launchMode和intent.flag有什么区别与联系?
launchMode是规定你自己的Activity启动的行为模式,而Intent.Flag是你期望由你启动的其他的Activity是什么样的行为模式。
所以这两者都能参与任务栈的管理,只是负责的对象不同。但是组合起来就很多种情况了,比较复杂。
  • 既然每一个taskrecord都有栈顶的ActivityRecord,那到底哪个task才是在前台的?
ActivityStackSupervisor中有变量mFocusedStack来标识哪个任务栈是当前使用的。
Ams中有mFocusedActivity来记录当前的focus Activity。
  • 各种模式最佳应用场景?为什么要区分这四种启动模式?
各种模式的存在肯定是有必要的,因为android组件化的思想使得弱化单独进程的概念。各个app内的组件可以相互调用,更多的规则组合可以兼顾需求和性能。
singleTop:适合启动同类型的 Activity,例如接收通知启动的内容显示页面
singleTask:适合作为程序入口
singleInstance:适合需要共享出去的界面
  • TaskAffinity是什么?对哪些模式有影响?
设置任务亲和性,上文已说主要是用于指定Activity需要的任务栈。
实际使用中一般配合SingleTask或SingleInstance使用。

Android中的TaskStack及启动模式的更多相关文章

  1. Android中Activity的四大启动模式实验简述

    作为Android四大组件之一,Activity可以说是最基本也是最常见的组件,它提供了一个显示界面,从而实现与用户的交互,作为初学者,必须熟练掌握.今天我们就来通过实验演示,来帮助大家理解Activ ...

  2. Activity中的四种启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  3. Android Activity 的四种启动模式 lunchMode 和 Intent.setFlags();singleTask的两种启动方式。

    原文:Android Activity 的四种启动模式 lunchMode 和 Intent.setFlags();singleTask的两种启动方式. Android Activity 的四种启动模 ...

  4. Android Activity的4种启动模式详解(示例)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5233269.html 先介绍下Android对Activity的管理,Android采用Task来管理多个A ...

  5. Android:图解四种启动模式 及 实际应用场景解说

    在一个项目中会包括着多个Activity,系统中使用任务栈来存储创建的Activity实例,任务栈是一种“后进先出”的栈结构.举个栗子,若我们多次启动同一个Activity.系统会创建多个实例依次放入 ...

  6. Android多任务切换与Activity启动模式SingleTask之间关系的分析

    这里会以多个场景列子进行分析,在分析之前先了解一下基本的概念. Task任务:一系列Activity的集合,这些Activity以栈的形式进行排列(后进先出). 那在什么时候系统会新建一个Task任务 ...

  7. Android开发9——Activity的启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. 一. ...

  8. android(十四)四种启动模式

    standard 启动的activity会每次都重新创建一个activity放到任务栈中.这是系统默认的启动模式. singleTop启动的activity,如果任务的栈顶刚好存在当前的activit ...

  9. Android Activity生命周期及启动模式

    曾经搞过许多东西,再熟练的东西一段时间没有碰都会生疏或忘记.后来体会到写成文档记录下来的重要性,但有些word或ppt记录下来的东西随着时间流逝会丢失,或者不愿去看.或许保存成博客的形式,会是更好的选 ...

随机推荐

  1. freeRTOS V10.0.1移植到STM32F407标准库 - 环境Keil5

    最近因为工作需要用到FreeRTOS,其实开始本人内心是拒绝的因为自己只学习过UCOSIII还没实际上过什么大又复杂的工程,但是谁让FreeRTOS他是Free的呢公司成本考虑肯定是不会选择USOS的 ...

  2. web 存储方式汇总:Cookies,Session, Web SQL; Web Storage(LocalStorage ,SessionStorage),IndexedDB,Application Cache,Cache Storage

    1 1 1 web 存储方式汇总: 旧的方式: Cookies; Session; Web SQL; 新的方式 HTML5 : Web Storage(LocalStorage ,SessionSto ...

  3. js console.log color all in one

    js console.log color all in one console.log color Chrome console.log 语法 / grammar %c, %s, css style ...

  4. SVG 与 Canvas 对比

    SVG 与 Canvas 对比 技术选型 SVG vs Canvas 应用场景 性能 GPU 加速 XML 数据存储 Canvas 2D Canvas 3D WebGL / OpenGL ES thr ...

  5. AI & HR

    AI & HR 数字化人才画像 人力资本数字化管理 通过"AI+数据+专家"的手段,将"数字化人才画像"作为服务起点与信息入口,扩展提供全场景的数字化人 ...

  6. Android Studio show whitespace & Android studio 设置注释缩进

    Android Studio show whitespace & Android studio 设置注释缩进 https://github.com/xgqfrms/flutter/issues ...

  7. Azure 信用卡扣款 1 美元 & Azure 中国客服

    Azure 信用卡扣款 1 美元 & azure 中国客服 Azure 免费帐户常见问题 https://azure.microsoft.com/zh-cn/free/free-account ...

  8. 19_MySQL表的内连接

    本节所涉及的SQL语句: -- 表连接查询 -- 查询每名员工(员工名字,编号)的部门信息(部门编号,部门名称) SELECT e.empno,e.ename,d.dname FROM t_emp e ...

  9. (十二)数据库查询处理之Query Execution(1)

    (十二)数据库查询处理之Query Execution(1) 1. 写在前面 这一大部分就是为了Lab3做准备的 每一个query plan都要实现一个next函数和一个init函数 对于next函数 ...

  10. 看完我的笔记不懂也会懂----less

    目录 Less学习 语法篇 注释 变量 映射(Maps) @规则嵌套和冒泡 less中的嵌套规则 less中的混合 less的运算 extend延伸/继承 less忽略编译(转义) 导入(Import ...