一、Activity的生命周期

Activity的管理同样是基于C/S架构的,所有的activity管理都在server端进行。在Server端对每个activity进行调度的同时,Client端负责响应各个生命周期的函数。

在Client端,对activity各个生命周期的响应都是在ActivityThread里进行操作。在本地,activity的生命周期如下图

ActivityThread提供给Server端的调度接口有以下几个:

scheduleLaunchActivity()

scheduleResumeActivity()

schedulePauseActivity()

scheduleStopActivity()

scheduleDestoryActivity()

scheduleRelaunchActivity()

scheduleWindowVisibility()

除了以上几个接口之外,还有其他的诸如scheduleConfigurationChanged()、scheduleNewIntent()这些接口,因为这些接口没有影响到activity的生命周期的流程,所以这里就不一一列举。下面我们来挑两个主要的接口来分析在本地端的调用流程。

1.ScheduleLaunchActivity

此接口的作用在于生成一个新的本地Activity对象,并且使之进入resume状态(或pause状态)。通常AMS会在两种情况下调用这个接口:点击应用图标打开新应用;从Activity B返回Activity A时,Activity A由于内存不足被kill。至于AMS如何确定何时调用此接口,属于AMS内部对activity的调度流程,后面会分析到。

在这里先说明下ActivityThread各函数的命名规则和函数调用方式。

上面列举的几个提供个AMS的接口全都以schedule为前缀,并且所有接口都是往主线程的handler里发送了命令消息之后立刻返回。这样所有的操作都会被转移到主线程上来。对应每一个schedule***函数,都有一个响应操作的handle***函数。在handle***函数里,会根据需要把操作进一步分解成几个动作,真正面向activity的操作统一命名为perform***。在perform***函数的内部,才会真正调用activity的生命周期函数(其实是通过Insturmentation来间接调用)。所以我们可以把所有的接口和方法进行分层:schedule->handle->perform->activity/Insturmation。

在scheduleLaunchActivity中,会往主线程handler发送一个“LAUNCH_ACTIVITY”消息,然后调用handleLaunchActivity。在handleLaunchActivity内部分解成两个动作:

a) performLaunchActivity

在这里完成了activity对象的创建和activity生存环境的创建。比如application对象的生成。接着调用activity.attach()完成Window和WindowManager的创建,并且记录了activity的环境变量如mToken、mActivityInfo等。到此为止,一个具有完整功能的Activity对象已经完成了初始化,接着会调用mInstrumentation.callActivityOnCreate()和activity.performStart()分别响应属于activity生命周期的onCreate()方法和onStart()方法。

b) handleResumeActivity

这个方法属于“handle层”的另一个方法,主要完成onStart()和onResume()的响应,在第二个例子中会说明。

2.ScheduleResumeActivity

顾名思义,此方法的作用是把一个activity置于resume状态。相应的,所有操作被转移到handleResumeActivity()中。对于handleResumeActivity,有两种情况会调用此方法:scheduleResumeActivity发送“RESUME_ACTIVITY”消息;handleLaunchActivity中的第二步。

在handleResumeActivity中也进一步分解成了两个动:

a) performResumeActivity

调用activity.performResume()方法,在activity.performResume()中会默认先调用performRestart(),performRestart()的作用是先检查activity是否处于stopped状态,如果是则调用performRestart()再调用performStart()。最后再响应activity的生命周期方法onResume()。

所以,新打开一个activity的响应流程是:

onCreate()->onStart()->onResume()

而返回一个后台activity的响应流程是:

onRestart()->onStart()->onResume()

b) 完成了第一步对activity生命周期的响应之后,在第二步这里主要是处理窗口的添加动作:把DecorView添加到WindowManager中。完成第二步操作之后,activity的内容便显示到了屏幕上。这个窗口的添加动作属于窗口管理中的一个步骤,具体可参考《Android窗口管理剖析》一文。

以下是部分主要接口到生命周期的响应的内部调用流程图

二、ActivityManagerService及其内部调度流程

\1. 数据结构分析

和窗口管理系统一样,所有的客户端activity在ActivityManagerService(简称AMS)内部都会有一个对应的ActivityRecord,对activity的管理也就是对ActivityRecord的管理。

AMS的相关代码在framework/base/services/java/com/android/server/am,主要的数据结构有:

ActivityManagerService

ActivityStack

ActivityRecord

TaskRecord

ProcessRecord

  1. ActivityManagerService是android框架服务,主要负责处理对android四大组件的管理和响应Client端的请求。此外还包括进程的产生和对WindowManagerService的操作。

  2. ActivityStack是专门实现对ActivityRecord的堆栈式管理而分离出来的一个模块。在Android2.2以前,对ActivityRecord的管理和调度都在ActivityManagerService实现。从android2.3以后,为了实现更好的解耦把对ActivityRecord的管理单独分离出来了,所有对ActivityRecord的调度操作都在ActivityStack里进行。其实Android里所谓的“Activity堆栈”,并不是真正的一个堆栈结构,而是一个ArrayList列表,在这个列表里记录了所有的ActivityRecord,ActivityStack所做的事情就是保证列表的第一个ActivityRecord(也就是“栈顶”)处于运行状态,并且排在列表后面的ActivityRecord的运行状态受到“栈顶”ActivityRecord的影响。

  3. ActivityRecord代表了一个Client端的Activity,记录了Activity的各种属性和管理状态。其中有介个关键的成员变量:

IApplicationToken.StubappToken

appToken作为此ActivityRecord的唯一标识,贯穿了AMS、Activity和WMS。

TaskRecordtask

task标识了此ActivityRecord所属的Task。在ActivityStack对ActivityRecord的位置调整中,更多的是以TaskRecord为单位进行的。如moveTaskToFront()、moveTaskToBack()等接口,会同时移动属于同一个Task的所有activity。 TaskRecord和ActivityRecord是一对多的关系,多个ActivityRecord可能指向同一个TaskRecord

ProcessRecordapp

app标识了Client端的Activity所在的进程。同样的,ProcessRecord和ActivityRecord是一对多的关系,多个ActivityRecord可能指向同一个ProcessRecord。通过访问ProcessRecord中的IApplicationThread可以直接操作Client端的ActivityThread。

  1. TaskRecord记录了task的id、名称等属性。

我们知道,Activity的管理是以Task为单位来进行的,多个行为类似的Activity会被归类到同一个Task中。一般来说,一个apk中的所有Activity都是属于同一个Task,并且Task以apk的包名来命名。但开发者可以在AndroidManifset.xml中通过android:taskAffinity属性给每个Activity配置不同的Task。而什么时候会新开一个Task,新开Task的名字等由ActivityStack里面的逻辑来判断,具体取决于AndroidManifest.xml中的配置和调用startActivity()时传递的flag。

  1. ProcessRecord记录了进程id、进程名字和各种用于调节优先级的状态。还包含了所有运行在该进程的Activity、Service、Receiver、Provider等组件。IApplicationThread thread记录了该进程中的主线程。当一个Acitivity第一次启动时,会首先调用Process.start(“android.app.ActivityThread”)来创建一个新进程并且生成一个ProcessRecord对象。当进程运行起来之后,该进程的主线程会调用Client端的ActivityThread.main()函数,在main()函数中完成Looper的prepare(),并且生成ActivityThread对象,接着在ActivityThread.attach()中调用IActivityManager.attachApplication()回到AMS,在AMS中完成ProcessRecord和IApplicationThread对象的绑定。接下来的流程就会把新Activity和ProcessRecord绑定。

关于ActivityManagerService、ActivityStack、ActivityRecord、TaskRecord、ProcessRecord的关系可用下图表示:

\2. ActivityStack内部调度流程

在整个调度流程中,ActivityStack记录了列表中每个ActivityRecord的当前状态,包括这9个状态:INITIALIZING, RESUMED, PAUSING, PAUSED, STOPPING, STOPPED,FINISHING, DESTROYING, DESTROYED。每个ActivityRecord在任何时刻都处于这9个状态中的其中一个。除此以外,ActivityStack还有几个变量用于辅助调度过程的:

ActivityRecord mResumedActivity

ActivityRecord mPausingActivity

boolean finishing

boolean stopped

ArrayListmStoppingActivities

mResumedActivity指向当前系统中的“栈顶”Activity,当“栈顶”Activity将要被暂停时,mResumedActivity为空,mPausingActivity指向该被暂停的Activity,直到Client端Activity响应onPause()之后回调AMS,mPausingActivity置空。finishing和stopped是ActivityRecord的两个boolean变量,finishing为true表示该Activity将要被销毁;stopped为true表示该Activity处于stopped状态(该stopped变量和Activity的STOPPED状态有重复的嫌疑,可认为是同等的)。

ActivityStack内部的调度围绕着这9个状态来进行,下面通过例子来分析其调度流程。

从Launcher(A)打开新应用(B)

  1. 在Clien端请求打开新Activity之后,ActivityStack首先创建一个ActivityRecord并将其置于“栈顶”,此时ActivityRecord处于INITIALIZING状态。

  2. 接着调用resumeTopActivityLocked()。在resumeTopActivityLocked()中检查mResumedActivity是否为空,此时mResumedActivity指向A,所以肯定不为空。

  3. 调用startPausingLocked()暂停A。此时将mResumedActivity置空,mPausingActivity指向A, 并且将A的状态置为PAUSING。接着调用Activity A的Client端的schedulePauseActivity()将其暂停。

  4. Client端的Activity 响应onPause()并且回调AMS的activityPaused()方法,将A的ActivityRecord的状态置为PAUSED,并把A添加到mStoppingActivities中。完成了A的暂停处理之后,会重新回到第2)步。在第二步中,此时mResumedActivity为空,接下来的流程会最终调用到Activity B 的Client端的scheduleLaunchActivity()。此时Activity B的状态变为RESUMED。

  5. ActivityB的Client端完成Activity的new和初始化并且响应onCreate()->onStart()->onResume(),然后回调AMS的activityIdle()方法告诉AMS已经运行完毕处于空闲状态。

  6. activityIdleLocked()主要是完成经过“堆栈”经过调整之后的“善后”工作。如根据finishing状态完成挂起的销毁操作,处理mStoppingActivities中的挂起stop操作。经过第4)步,A已经在mStoppingActivities中,所以接下来会调用A的Client端的scheduleStopActivity(booleanvisible),在Client端,根据接口参数visible判断,如果visible为false则响应onStop(),否则不响应。在ActivityStack中,visible的值是通过从上到下的计算得出的。如果“栈顶”Activity为fullscreen,则处于“栈顶”底下的其他activity的visible全为false。这个计算过程在第4)步中会执行一次或多次。在执行stop操作时,Activity A的状态从PAUSED变成STOPPING,再变成STOPPED。

在第4)步的处理中,会继续调用resumeTopActivityLocked(),在resumeTopActivityLocked()中,会判断ActivityRecord中的ProcessRecord app是否为空,这里有两种情况:

a) app不为空。

这种情况的前提是,Activity B并不是新打开的而是在一直在后台,并且其进程没有由于内存回收而杀掉。在这种情况下,会直接调用scheduleResumeActivity(),Client端会进行响应:onRestart()->onStart()->onResume()

b) app为空

app为空有三种情况,第一种是ActivityB之前一直在后台运行,由于内存不足被杀掉;第二种是Activity B是新打开的,并且不存在对应的进程;第三中情况是,Activity B 是新打开的,但是其进程仍在运行中。在第一、二种情况中,AMS会启动新进程,并完成Activity B和新进程的ProcessRecord的绑定。

在这三种情况中,最后都会调用scheduleLaunchActivity(),Client端会进响应:onCreate->onStart()->onResume()。

所以,从Launcher(A)打开新Activity (B)的生命周期响应流程如下:

A->onPause()

B->onCreate()

B->onStart()

B->onResume()

A->onStop() (如B不为fullscreen则不响应此方法)

整个调度流程可用下图表示:

关于ActivityStack内部的其他参与调度的函数,大概整理了一下,得到下面的函数调用流程图

转自:http://www.voidcn.com/blog/huanxido/article/p-3139817.html

Activity管理(三):activity内核管理方案详细讲解相关推荐

  1. vue状态管理存取数据_vue状态管理vuex从浅入深详细讲解

    1.vuex简介以及创建一个简单的仓库 vuex是专门为vue框架而设计出的一个公共数据管理框架,任何组件都可以通过状态管理仓库数据沟通,也可以统一从仓库获取数据,在比较大型的应用中,数据交互庞大的情 ...

  2. arm板telnetd为什么运行不了_一种基于ARM的嵌入式系统开发的方案详细讲解

    背景介绍 在日益信息化的社会中,各种各样的嵌入式系统已经全面渗透到日常生活的每一个角落.嵌入式系统的功能越来越复杂,这就使得一个嵌入式系统产品从市场需求立项到方案选择.样机研制.定型量产所需要的开发费 ...

  3. 详细讲解从用户空间申请内存到内核如何为其分配内存的过程

    Linux内存管理 摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法.力求从外到内.水到渠成地引导网友分析Linux ...

  4. 深度linux_工程师深度:学通Linux内核(含详细代码)

    内核探索工具类 Linux的具体概述这里就不多说了,今天主要讲的是Linux内核中常用的数据结构和语法的使用,并简述一些工具和实用程序,从而获取理解内核内幕所需要的信息,还会介绍一下在每个内核子系统所 ...

  5. android 生命周期管理,Android Activity生命周期和堆栈管理的详解_Android_脚本之家...

    Activity的生命周期 Activity是Android中的四大组件之一,也是最基本,最重要的组件,是android系统提供一个可视化的,能与用户交换的组件. 系统提供的组件,不需要用户实例化,用 ...

  6. 【Android 插件化】Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  7. 详细讲解Linux内核源码内存管理(值得收藏)

    Linux的内存管理是一个非常复杂的过程,主要分成两个大的部分:内核的内存管理和进程虚拟内存.内核的内存管理是Linux内存管理的核心,所以我们先对内核的内存管理进行简介. 一.物理内存模型 物理内存 ...

  8. 《Linux内核设计与实现》读书笔记 第三章 进程管理

    第三章进程管理 进程是Unix操作系统抽象概念中最基本的一种.我们拥有操作系统就是为了运行用户程序,因此,进程管理就是所有操作系统的心脏所在. 3.1进程 概念: 进程:处于执行期的程序.但不仅局限于 ...

  9. 深入理解Activity启动流程(三)–Activity启动的详细流程2

    本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--A ...

最新文章

  1. UA SIE545 优化理论基础2 凸函数 概念 理论 总结
  2. redis设置数据库数量databases
  3. 前端学习(2886):如何短时间内实现v-for 组件化设计方案
  4. ADO.NET与Sql Server和Access的连接
  5. SAP License:ERP的实施要点
  6. PHP网站开发有哪些框架,罗列几款时下高人气的PHP开发框架
  7. WordPress纯PHP代码实现记录搜索引擎蜘蛛爬行记录
  8. S2D_基于深度学习的视觉稠密建图和定位_相关文章
  9. Windows10桌面美化——打造简洁高效美观桌面
  10. postman导入postman_collection文件
  11. 月薪3千与3万文案的区别!一字千金就体现在细微之处
  12. 不懂zencart该如何找出路-新手soho建站指南
  13. 游戏开发程序员可能会遇到的英文单词
  14. 4.2 char类型介绍
  15. 爱看广场舞的老爷爷的笔记---ifconfig命令无法使用
  16. 【论文笔记】Towards Making Systems Forget with Machine Unlearning
  17. 基于全志D1-H和XR806的名贵植物监控装置
  18. MyDockFinder 5.5体验极致模拟 Mac OS 系统桌面,完美支持最新版Win10 系统,可使用系统级模糊效果
  19. 《Interpret Neural Networks by Identifying Critical Data Routing Paths》CDRPs总结
  20. android 系统自带分享文字+图片到微信朋友圈

热门文章

  1. java frame paint_一个简单的java frame画图(paint)问题
  2. 求列表最大元素不用max_python3实现从一个无序列表中求取连续元素之和中最大的和...
  3. Beta 冲刺(4/7)
  4. 强悍的远程桌面管理器
  5. 数据库事务的悲观锁和乐观锁
  6. Python 结巴分词(1)分词
  7. 微信内置浏览器的JsAPI(WeixinJSBridge续)[转载]
  8. Android数据存储之SD卡
  9. Aspose.Cells小实例
  10. Nginx小功能合集