前言

本文主要涉及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. 牛客多校第五场B generator1(十进制矩阵快速幂)题解

    题意: 已知 \(X_i = a * X_{i - 1} + b * X_{i - 2}\),现给定\(X_0,X_1,a,b\),询问\(X^n \mod p\),其中\(n <= 10^{1 ...

  2. 【原】无脑操作:Centos 7.6 + MariaDB + Rsyslog + LogAnalyzer环境搭建

    背景: 网络安全法第三章第二十一条明确规定"采取监测.记录网络运行状态.网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月". 为了满足合规性的要求,应当建设相应的日 ...

  3. 006.NET 项目建立+传值

    1. 创建项目 2.传值(控制器向视图传递) 接收值 3.视图向控制器传递 4.session配置

  4. HTML教程(看完这篇就够了)

    HTML教程 超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言.您可以使用 HTML 来建立自己的 WEB 站点,HTML 运 ...

  5. js map & Number

    js map & Number const regionIds = `1,2,3`; // "1,2,3" regionIds.split(',').map(Number) ...

  6. VuePress & Markdown Slot

    VuePress & Markdown Slot refs https://vuepress.vuejs.org/zh/guide/markdown-slot.html#为什么需要-markd ...

  7. web 前端工具: Gulp 使用教程

    1 1 1 Gulp 使用教程: 1 1 1 1 1 1 1 1 ERROR: ./app.js 当前目录路径: ./ 当前目录路径: ./ 1 1 1 1 1 参考资源: http://webpac ...

  8. You Don't Know Chrome Features

    You Don't Know Chrome Features URL auto convert to QR Code click the tab URL address click QRCode ic ...

  9. Chrome V8 引擎源码剖析

    Chrome V8 引擎源码剖析 V8 https://github.com/v8/v8 array & sort https://github.com/v8/v8/search?l=Java ...

  10. Online analog video interview

    Online analog video interview 在线模拟视频面试 English 口语 https://www.pramp.com/#/ https://www.pramp.com/faq ...