Activity是Android四大组建之一,负责用户交互界面展示,其重要性不可言喻。Android系统由ActivityManagerService负责管理Activity。熟悉Activity的启动,将对我们学习了解ActivityManagerService大有裨益。本文基于AndroidP将以首次点击桌面应用图标的方式为线,分析Activity的启动,包括分析应用进程启动。文中将涉及不少应用启动的字眼,为了避免理解上的误解,先做一解释,其实应用启动的过程,便会伴随着Activity的启动,分析应用的启动流程包括Activity的启动。这里不讨论无界面应用(比如只托管service的应用进程启动),特指有界面的应用程序。由于篇幅原因文章中,只列举一些启动过程中的关键代码,将会更多介绍AMS相关的内容,至于涉及到WMS等其他内容暂不做重点讨论。我们在理解这些关键的基础上,回头再看Activity的启动将“如履平地”般容易。
以小见大-以Log窥Activity启动全貌(Log来源小米8手机Android8.1系统,与P相差不大)
以上这份Log基本可以说是涵盖了Acitivity启动过程中所有的关键点信息,作为初学者,可能不知所以然,不过没关系,本文将详细介绍,这其中的原理。你可以获得Activity启动的耗时时间,你可以获得Activity启动所在的Stack和归属的Task id号……
基础普及-一张小图解Activity
Activity 生命周期回调方法汇总表。
始终后接 onStart()。
始终后接 onStart()
如果 Activity 转入前台,则后接 onResume(),如果 Activity 转入隐藏状态,则后接 onStop()。
或
onStop
始终后接 onPause()。
如果 Activity 返回前台,则后接 onResume(),如果 Activity 转入对用户不可见状态,则后接 onStop()。
或
onStop
如果 Activity 恢复与用户的交互,则后接 onRestart(),如果 Activity 被销毁,则后接 onDestroy()。
或
onDestroy
了解Activity,就要知道Activity的生命周期(Lifecycle),知道Activity各个生命周期出现的场景。如图所示,Activity从开始到结束可细分为:onCreate,onStart,onResume,onPause,onStop,onDestory。Activity的启动方式,显示,隐式:
一般我们都是如此启动,当然我们也可以通过配置AndroidManifest我们的某个Activity作为应用启动首选Activity:
Android规定Activity有四种启动方式standard,singleTop,singleTask,singleInstance。
Android应用程序的入口ActivityThread-好比Java程序的main主函数
讲Activity启动之前,必须强调一下ActivityThread,ActivityThread的main方法便是Android应用程序的入口,代表应用程序执行开始。
Android应用程序的事件操作是基于消息机制的,简单概述一下Android的消息机制,Android消息机制三大核心Handler,MessageQueue,Loop。Handler负责处理消息,MessageQueue用来保存消息,Loop用来循环取消息。ActivityThread的main方法的最后一行Looper.loop()(这是一个死循环,后续介绍Android消息机制的时候详细解释)意思就是我们的应用进入工作循环模式,开始运行,准备接受处理消息了。直白的说就是应用跑起来了。既然应用程序已经运行起来了,那么我们就需要Activity界面展示了。我们就要启动我们的Activity了,本文将以首次点击QQ桌面图标启动QQ首Activity为线,来分析Activity的启动流程及原理。
弹指一击QQ应用桌面图标-手机系统都经历了啥?
当我们首次通过点击QQ桌面图标来启动QQ应用时,QQ启动的动作请求来自桌面应用miui Launcher,经过一些列的调用,便请求AMS启动QQ应用,最终调用AMS的ActivityStarter的startActivity方法,该方法可以认为是Activity启动过程中的第一步,负责启动时最基本的检查操作,比如检查Activity信息是否存在,创建ActivityRecord等:
该方法执行会输出对应Log
经过层层调用便会继续调用ActivityStarter的startActivityUnchecked方法,从命名可以看出,该方法中应该不做任何检查工作,之负责Activity启动时在AMS中的一些初始化的任务,我们知道Activity启动涉及启动flag,Task,Stack信息,我们需要做一个初始化:
startActivityUnchecked方法还会为启动的Activity创建或复用对应的Stack和Task。更多Stack和Task信息请查看文章“任务(Task)和堆栈(Stack)”google网站翻译内容,介绍的非常详细。
调用setTaskFromReuseOrCreateNewTask创建或者复用当前的启动Activity所在的Task,本例是创建。当应用内部Activity跳转排除启动模式和启动Flags干扰时,一般会复用之前Activity所在的Task。创建TaskRecod由ActivityStack.createTaskRecord完成,期间还会调用TaskRecord.createWindowContainer创建对应的TaskWindowContainerController,同时关联TaskRecord和TaskWindowContainerController,对应如下Log:
当Task创建好了之后,我们已经将Task和Activity关联好,并且Task的头部Activity便是我们要启动的Activity,继续执行启动,对应Log如下:
其中mTargetStack.startActivityLocked方法,对应如下Log:
当我们创建设置好Task和Stack之后,我们就要真正开始resume启动激活Activity了,继续执行 mSupervisor.resumeFocusedStackTopActivityLocked最终经过层层调用直到ActivityStack的resumeTopActivityInnerLocked:这也是启动过程中第一次调用该方法,由于整个启动过程函数调用相当复杂,这里暂且先预览一下整个执行过程
第一次调用resumeTopActivityInnerLocked,我们会发现参数prev和next都是指向要启动的QQ的SplashActivity,而当前手机显示的应用是miui launcher,因此我们在启动新的Activity之前需要暂停当前正在显示的应用,因此此时会输出对应的Log:
当miui launcher成功暂停的时候,输出对应Log:
接着会继续第二次执行resumeTopActivityInnerLocked去真正的启动我们的QQ,但是由于QQ首次启动,因此我们先创建其进程,当创建OK好QQ进程之后,会调用QQ进程的ActivityThread的main函数,这样QQ进程便成功启动了,对应Log:
但是此时QQ应用进程在系统中的名称并未设置为对应的QQ的进程名,会在bindApplication操作中进行设置。对应Log:
程创建好之后,继续Activity启动流程,从代码流程中我们可以看出最终是要执行realStartActivityLocked这个方法的,对应会输出Log:
realStartActivityLocked方法中会调用stack.minimalResumeActivityLocked(r); 对应会输出Log
之后会到QQ应用进程去启动首界面SplashActivity,对应从应用程序中会输出Log:
此时应用进程便会开始绘制自己的界面,并与WMS和SurfaceFlinger通信,进行界面展示,至于Activity的界面绘制流程,计划后续会再进行介绍,此处不重点分析。
任务(Task)和堆栈(Stack)-翻译自google网站
任务(Task)是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(Stack)中,AMS中分别以TaskRecord和ActivityStack表示,Activity则用ActivityRecord表示。
大多数情况下设备主屏幕即launcher界面,就是任务的起点,当用户触摸应用启动器中的图标(或主屏幕上的快捷方式)时,该应用的任务将出现在前台。 如果应用不存在任务(应用最近未曾使用),则会创建一个新任务,并且该应用的“主”Activity 将作为堆栈中的根 Activity 打开。
当前 Activity 启动另一个 Activity 时,该新 Activity 会被推送到堆栈顶部,成为焦点所在。 前一个 Activity 仍保留在堆栈中,但是处于停止状态。Activity 停止时,系统会保持其用户界面的当前状态。 用户按“返回”按钮时,当前 Activity 会从堆栈顶部弹出(Activity 被销毁),而前一个 Activity 恢复执行(恢复其 UI 的前一状态)。 堆栈中的 Activity 永远不会重新排列,仅推入和弹出堆栈:由当前 Activity 启动时推入堆栈;用户使用“返回”按钮退出时弹出堆栈。 因此,返回栈以“后进先出”对象结构运行。
下图 通过时间线显示 Activity 之间的进度以及每个时间点的当前返回栈,直观呈现了这种行为。
显示任务中的每个新 Activity 如何向返回栈添加项目。 用户按“返回”按钮时,当前 Activity 随即被销毁,而前一个 Activity 恢复执行。
如果用户继续按“返回”,堆栈中的相应 Activity 就会弹出,以显示前一个 Activity,直到用户返回主屏幕为止,当所有 Activity 均从堆栈中移除后,任务即不复存在。
任务是从用户角度来管理Activity的,当用户开始新的任务或者按home键回到主屏幕时,可以移到到后台,当该任务到后台时,任务中所有的Activity全部处于停止状态,但是任务的堆栈顺序是不会改变的,从window的角度来说,该任务只是失去焦点而已,
两个任务:任务 B 在前台接收用户交互,而任务 A 则在后台等待恢复。
当该任务获得焦点时,用户即可回到离开时的状态。但是如果后台运行着多个任务,系统为了保持流畅性,可能会开始销毁后台的Activity,以回收内存资源,从而导致Activity的状态丢失,详细请参见Activity状态
正常情况下,由于栈中的 Activity 永远不会重新排列,因此如果应用允许用户从多个 Activity 中启动特定 Activity,则会创建该 Activity 的新实例并推入堆栈中(而不是将 Activity 的任一先前实例置于顶部),因此,应用中的一个 Activity 可能会多次实例化(即使 Activity 来自不同的任务)如下图
但是,如果我们不希望 Activity 多次实例化,则可修改此行为,详细请参见Task管理。系统中Activity和Task的默认行为如下:
-
当 Activity A 启动 Activity B 时,Activity A 将会停止,但系统会保留其状态(例如,滚动位置和已输入表单中的文本)。如果用户在处于 Activity B 时按“返回”按钮,则 Activity A 将恢复其状态,继续执行。
-
用户通过按“主页”按钮离开任务时,当前 Activity 将停止且其任务会进入后台。 系统将保留任务中每个 Activity 的状态。如果用户稍后通过选择开始任务的启动器图标来恢复任务,则任务将出现在前台并恢复执行堆栈顶部的 Activity。
-
如果用户按“返回”按钮,则当前 Activity 会从堆栈弹出并被销毁。 堆栈中的前一个 Activity 恢复执行。销毁 Activity 时,系统不会保留该 Activity 的状态。
- 以上就是本篇文章【ActivityManagerService解读之Activity启动初探】的全部内容了,欢迎阅览 ! 文章地址:http://xiaoguoguo.dbeile.cn/news/431.html 资讯 企业新闻 行情 企业黄页 同类资讯 首页 网站地图 返回首页 多贝乐移动站 http://xiaoguoguo.dbeile.cn/mobile/ , 查看更多