- Android 触摸屏事件派发机制详解与源码分析一 View 篇
- Android 触摸屏事件派发机制详解与源码分析二 ViewGroup 篇
- Android 触摸屏事件派发机制详解与源码分析三 Activity 篇
- Android 应用 setContentView 与 LayoutInflater 加载解析机制源码分析
- Android 应用 Context 详解及源码解析
- Android 异步消息处理机制详解及源码分析
- Android 应用 Activity、Dialog、PopWindow、Toast 窗口添加机制及源码分析
- Android ListView 工作原理完全解析,带你从源码的角度彻底理解
- Activity 启动过程全解析
- Android 应用 AsyncTask 处理机制详解及源码分析
- 说说 PendingIntent 的内部机制
- Android Activity.startActivity 流程简介
- Activity 界面显示全解析
- 框架层理解 Activity 生命周期(APP 启动过程)
- APK 安装过程及原理详解
- Android 构建过程简述
- Android 应用层 View 绘制流程与源码分析
框架层理解 Activity 生命周期(APP 启动过程)
http://m.blog.csdn.net/blog/yhc13429826359/19977429
1 生命周期图
2 主要类图调用
上面类图关系中包含两个进程,一个是应用程序进程,另一个是 AMS 进程,所以会涉及到进程间通信,android 进程间通信用的是 Binder 通信。
2.1 客户进程
ØActivityThread
可以看到该类有一个 main 方法,其实它是 android 一个应用程序的入口,每启动一个应用进程,都会创建 ActivityThread 与之对应的实例,是应用程序的 UI 线程,Android 进程启动时会建立消息循环。负责管理应用程序的生命周期,执行系统广播及其 ActivityManagerService 请求执行的操作。属于客户端对象。
ØApplicationThread&ApplicatinThreadNative
ApplicationThread 用来实现 ActivityManagerService 与 ActivityThread 之间的交互。在 ActivityManagerService 需要管理相关 Application 中的 Activity 的生命周期时,通过 ApplicationThread 与 ActivityThread 通讯,ApplicationThreadNative 是 ApplicationThread 在客户端的实现。
ØApplicationThreadProxy
ApplicationThreadProxy 是 ApplicationThread 在服务器端的代理。负责和服务器端的 ApplicatingThreadNative 通讯。
AMS 就是通过该代理与 ActivityThread 进行通信的。
ØActivity& Intrumentation
Activity 是应用程序真正做事情的类,每一个应用程序只有一个 Instrumentation 对象,每个 Activity 内都有一个对该对象的引用。Instrumentation 可以理解为应用进程的管家,ActivityThread 要创建或暂停某个 Activity 时,都需要通过 Instrumentation。通俗的理解,Instrumentation 与 ActivityThread 的区别,前者像是一个“家庭”里的“管家”,后者是负责创建这个“家庭”,并负责对外打交道,比如接收 AMS 的通知等。
2.2 AMS 进程
这里说的 AMS 进程,实际指的是 System_server 进程,System_server 进程起来的时候启动 AMS 服务,AMS 实际是 ActivityManagerService 的缩写。
ØActivityManagerService
管理 Activity 的生命周期
ØActivityManagerNative
ActivityManagerService 在服务器端的实现,客户端的请求调用 ActivityManagerProxy 后,通过 IBinder,最终会在 ActivityManagerNative 中实现。ActivityManagerNative 再通过调用 ActivityManagerService 的相关功能,以完成客户端请求。
ØActivityManagerProxy
ActivityManagerService 的在客户端的代理。负责和服务器端的 ActivityManagerNative 通讯。
ØActivityStack
Activity 在 AMS 的栈管理,用来记录已经启动的 Activity 的先后关系,状态信息等。通过 ActivityStack 决定是否需要启动新的进程。
ØActivityRecord
ActivityStack 的管理对象,每个 Activity 在 AMS 对应一个 ActivityRecord 来记录 Activity 的状态以及其他的管理信息。
ØTaskRecord
AMS 抽象出来的一个“任务”的概念,是记录 ActivityRecord 的栈,一个“Task”包含若干个 ActivityRecord。AMS 用 TaskRecord 确保 Activity 启动和退出的顺序。
ØProcessRecord
一个 Apk 文件运行时会对应一个进程,ProcessRecord 正是记录一个进程中的相关信息。
3startActivity 流程
在 Android 系统中,应用程序是由 Activity 组成的,因此,应用程序的启动过程实际上就是应用程序中的默认 Activity 的启动过程。启动 Android 应用程序中的 Activity 的两种情景,第一,在 android 设备屏幕中点击应用程序图标的情景就会引发 Android 应用程序中的默认 Activity 的启动,从而把应用程序启动起来,这种启动方式的特点是会启动一个新的进程来加载相应的 Activity。第二,应用程序内部启动非默认 Activity 的过程的源代码,这种非默认 Activity 一般是在原来的进程和任务中启动的。在 Android 的 Activity 管理机制中,当退出 Activity 的时候,在某些情况下并没有立即把该 Activity 杀死,而是将其暂时保存起来,当第二次调用 startActivity 启动该 Activity 的时候,就不需要再创建该 Activity 的实例,直接恢复 Activity 即可。
3.1 调用流程图
对用户来讲,启动一个 Activity 有以下几种方式:
Ø在应用程序中调用 startActivity() 启动指定的 Activity
Ø在 Home 程序中点击一个应用图标,启动新的 Activity
Ø按“Back”键,结束当前 Activity,自动启动上一个 Activity
Ø长按“Home”键,显示当前列表中,从中选则一个启动
对于 AMS 内部讲,启动一个 Activity 有三种方式,如上图中的①②③分支:
①目标 Activity 的对象已经存在,那么直接 resume 该 Activity
②目标 Activity 所在的进程不存在,那么需要创建进程,并在新的进程中启动该 Activity
③目标 Activity 所在进程已经存在,那么直接在已存在进程中启动该 Activity
3.2 在新的进程中启动
以在 Home 程序中点击一个应用图标,启动 MainActivity 为例子,介绍如下。
时序图如下图:
以上时序图包含 35 步骤调用,下面逐一讲解:
3.2.1(1~4),Launcher 中发送 startActivity 请求
在 Android 系统中,应用程序是由 Launcher 启动起来的,其实,Launcher 本身也是一个应用程序,其它的应用程序安装后,就会 Launcher 的界面上出现一个相应的图标,点击这个图标时,Launcher 就会对应的应用程序启动起来。
Launcher 继承与 Activity,Activity 类的有个成员变量 mInstrumentation 是,它的类型是 Intrumentation,它用来监控应用程序和系统的交互。
Instrumentation.execStartActivity:
publicActivityResult execStartActivity( |
这里的 ActivityManagerNative.getDefault 返回 ActivityManagerService 的远程接口,即 ActivityManagerProxy 接口。
3.2.2(5-8) AMS 接收客户端 startActivity 请求
客户端通过 Binder 调用,最终调用到 ActivityStack.startActivityLocked:
final intstartActivityLocked(IApplicationThread caller, |
startActivityLock() 主要做了一下几件事:
①处理传进来的参数 caller,得到调用者的进程信息,并保存在 callerApp 变量中,这里就是 Launcher 应用程序的进程信息了。
②处理 FLAG_ACTIVITY_FORWARD_RESULT 标志。该标志的特殊作用,就是能跨 Activity 传 Result,比如 A1->A2,A2 带该标志启动 A3,那么 A3 调用 setResult,然后 finish(),结果将直接返回到 A1
③创建一个临时的 ActivityRecord 对象,该对象只为了后面调用过程中的各种对比,不一定会最终加入到 mHistory 列表中。
④判断 mPendingActivityLaunches 列表是否有等待的 Activity 要启动,如果有先启动等待的 Activity
⑤调用 startActivityUncheckedLocked() 方法。此时要启动的 Activity 已经通过检验,被人认为是一个正当的启动请求。
3.2.3(9) 创建新的 Task
调用 ActivityStack.startActivityUncheckedLocked() 处理 Task 问题,因为这里我们是新启动一个 apk,所以将创建新的 Task,newTask=true,并调用 ActivityStack.startActivityLoacked():
privatefinal void startActivityLocked(ActivityRecord r, booleannewTask, |
注意 AtivityStack 中有两个 startActivityLoacked() 方法,这里调用的是带四个参数的,即 startActivityLocked(ActivityRecord r, booleannewTask,boolean doResume, booleankeepCurTransition),其中,r 为将要启动的 Activity,newTask=true,doResume=true,在这个方法中,将 r 放到 mHistory 的最后面 doResume=true,所以调用 resumeTopActivityLocked(null)。关于 Task 的概念比较复杂,这里先不讲解。
3.2.4:(10) 运行 mHistory 中最后一个 ActivityRecord
ActivityStack. resumeTopActivityLocked(null)
finalboolean resumeTopActivityLocked(ActivityRecord prev) { |
调用 resumeTopActivityLocked(null) 启动真正的 Activity。
①调用 topRunningActivityLocked() 方法取出当前正在运行的 ActivityRecord 对象
②判断 mHistory 中是否有记录,如果没有就意味着还没有启动任何的 Activity,需要首先调用 mService.startHomeActivityLocked() 方法启动所谓的“主界面程序”。当然我们这里 mHistroy 已经有记录了。
③判断正在执行的 Activity 是否和目标 Activity 一样,如果一样,则直接返回。
④判断当前系统是否处于休眠涨停,如果是,则返回。这里继续往下执行。
⑤从 mStoppingActivities、mWaitingVisibleActivities 和 mGoingToSleepActivities 中删除目标对象,因为接下来将要被启动。
⑥判断当前是否在暂停某个 Activity,如果是则还不能运行。这里 mPausingActivity=null,所以继续往下执行。
⑦判断当前是否有 Activity 在运行,如果有则先需要暂停当前的 Activity。因为我们是在 Lancher 中启动 mainActivity,所以当前 mResumedActivity!=null,所有调用 startPausingLocked(userLeaving, false);
3.2.5(11~16) 暂停当前运行 Activity
①调用 ActivityStack.startPausingLocked() 暂停当前 Activity。
②判断运行当前 Activity 的进程是否存在。在这里 if (prev.app != null&& prev.app.thread !=null) 为真。其中,prev.app 为记录启动 Lancher 进程的 ProcessRecord,prev.app.thread 为 Lancher 进程的远程调用接口 IApplicationThead,所以可以调用 prev.app.thread.schedulePauseActivity,到 Lancher 进程暂停指定 Activity。
③在 Lancher 进程中消息传递,调用 ActivityThread.handlePauseActivity(),最终调用 ActivityTHread.performPauseActivity 暂停指定 Activity。接着通过 Binder 通信,通知 AMS 已经完成暂停 ActivityManagerNative.getDefault().activityPaused(token).
3.2.6(17~20) AMS 处理暂停 Activity 事情
在 Launcher 通过 Binder 进程间通信机制通知 AMS,它已经准备就绪进入 Paused 状态,在 ActivityStack.completePauseLocked() 中完成暂停:
private final void completePauseLocked(){ |
①给 prev 赋值 mPausingActivity,即上一个被执行的 Activity,即 Launcer
②如果 prev 的 finishing 为 true,说明上一个 Activity 已经完成,因此需要调用 finishCurrentActivityLocked() 执行相关操作。一般的流程不会为 true,这个条件似乎只有内存回收的时候才会被执行。
③将 mPausingActivity 变量置为空
④调用 resumeTopActivityLocked 方法正式启动目标 Activity,即 MainActivity
3.2.7:(21~23) 正式启动目标 Activity
调用 AcivityStack.resumeTopActivityLocked:
final booleanresumeTopActivityLocked(ActivityRecord prev) { |
①该方法在 3.2.4 步骤中调用过,那时是因为 mResumedActivity != null,有 Activity 正在运行,所以去执行了 startPausingLocked 暂停 Laucher 去了。这时候,mResumedActivity=null,所以继续往下执行。
②判断讲要启动的 Activity 的客户进程是否存在,这里 next.app != null &&next.app.thread != null 为 false
③调用 ActivityStack.startSpecificActivityLocked
private final voidstartSpecificActivityLoc return; |
④客户进程不存在,app!= null && app.thread !=null 为 false,所以调用 mService.startProcessLocked() fork 一个新的进程。
3.2.8(24) fork 一个新的进程
①AMS 通过 Socket 通信,向 Zygote 发送一个创建进程请求,Zygote 创建新进程。
②创建好进程后,调用 ActivityThread.main()。到此,我们到了新了一个进程中,也是程序的入口出。
③调用 ActivityThread.attach() 开始新的应用程序,接着同过 Binder 通信通知 AMS,新的进程已经创建好了,可以开始新的程序了。
3.2.9(26~28) AMS 准备执行目标 Activity
目标进程启动后,报告给 AMS,自己已经启动完毕可以启动 Activity 了,这里通过 IPC 调用 AMS 的 attachApplication 方法完成。
ActivityManagerService.attachApplication():
public final voidattachApplication(IApplicationThread thread) { |
①根据 Binder.getCallingPid(),或得客户进程 pid,并调用 attachApplicationLocked(IApplicationThreadthread,int pid)
②在 attachApplicationLocked 中,根据 pid 找到对应的 ProcessRecord 对象,如果找不到说明改 pid 客户进程是一个没经过 AMS 允许的进程。
private final booleanattachApplicationLocked(IApplicationThread thread, |
③为 ProcessRecordapp 对象内部变量赋值
④确保目标程序(APK)文件已经被转换为了 odex 文件。Android 中安装程序是 APK 文件,实际上是一个 zip 文件。
⑤调用 ActivityStack.realStartActivityLocked 通知客户进程运行指定 Activity.
⑥调用 ApplicationThread.scheduleLaunchActivity,启动指定 Activity。
3.2.10:(29~35) 客户进程启动指定 Activity
AMS 通过 IPC 通行,通知客户进程启动指定 Activity
①调用 ApplicationThread.scheduleLaunchActivity
②经过 Handler 消息传动,调用 ActivityThread.handleLaunchActivity()
③调用 ActivityThread.performLaunchActivity() 完成 Activity 的加载,并最终调用 Activity 生命周期的 onCreate() 方法
④performLaunchActivity 返回,继续调用 ActivityThread.handleResumeActivity(),该方法内部又调用 ActivityThread.performResumeActivity(),其内部仅仅调用了目标 Activity 的 onResume() 方法。到此 Activity 启动完成。
⑤添加一个 IdleHandler 对象,因为在一般情况下,该步骤执行完毕后,Activity 就会进入空闲状态,所以就可以进行内存回收。
3.3 在已有进程中启动
在已有的进程中启动 Activity,也就是在一个应用程序中启动内部 Activity,其过程跟 3.2 小节大致一样,这里我们不会像 3.2 小节详细分析每一步骤,我们只看差别的地方。这里以启动 subActivity 为例子。时序图如下:
以上时序图包含 29 步骤调用,下面逐一讲解:
3.3.1(1~3) 在 MainActivity 启动 Activity
这一步跟 3.2.1 小节一样
3.3.2(4~7) AMS 接收客户端 startActivity 请求
这一步跟 3.2.2 小节一样
3.3.3(8) 不需要创建新的 Task
调用 ActivityStack.startActivityUncheckedLocked() 处理 Task 问题,因为这里我们是在已有应用中 startActivity,也不设置标志要在新的 Task 中启动 Activity,所以不创建新的 Task,newTask=false,并调用
ActivityStack.startActivityLoacked():
privatefinal void startActivityLocked(ActivityRecord r, booleannewTask, |
注意 AtivityStack 中有两个 startActivityLoacked() 方法,这里调用的是带四个参数的,即 startActivityLocked(ActivityRecord r, booleannewTask,boolean doResume, booleankeepCurTransition),其中,r 为将要启动的 Activity,newTask=false,doResume=true,在这个方法中,将 r 放到 mHistory 的最后面 doResume=true,所以调用 resumeTopActivityLocked(null)。
3.3.4(9) 准备启动 mHistory 中最后一个 Activity
这一步跟 3.2.4 小节一样
3.3.5(10~15) 暂停 MainActivity
这一步跟 3.2.5 小节一样
3.3.6(16~19) AMS 处理暂停 MainActivity
这一步跟 3.2.6 小节一样
3.3.7(20~22) 正式启动目标 Activity
调用 AcivityStack.resumeTopActivityLocked:
final booleanresumeTopActivityLocked(ActivityRecord prev) { |
①调用 startSpecificActivityLocked(next, true,true)
private final voidstartSpecificActivityLoc return; |
②subActivity 进程已经存在,app != null&& app.thread !=null 为 true,所以调用 realStartActivityLocked。
finalboolean realStartActivityLocked(ActivityRecord r, |
③调用 ApplicationThread.scheduleLaunchActivity,启动指定 Activity。
3.3.8(23~29) 客户进程启动指定 Activity
这一步跟 3.2.10 是一样的
3.4 在已有的 ActivityRecord 中恢复指定 Activity
经过上面 3.2 和 3.3 小节,现在对 Activity 的启动流程应该是比较清晰的了,这一节就简单的讲下恢复 Activity 的流程。当 ActivityRecord 已经记录有一个 Activity,如果再次调用 startActivity,并没有标志要创建 Activity 新的实例,那么就可以直接恢复该 Activity。
①启动一个 Activity,跟前面 3.2 节一样,都需要暂停当前正在运行的 Activity,暂停流程这里就不讲了,完成暂停后,调用 ActivityStack.resumeTopActivityLocked()。
②因为 AMS 和 ActivityTHread 的 IPC 通信,resumeTopActivityLocked 会被反复调用几次,每次都会根据一些变量值的差异,走不同的流程。
finalboolean resumeTopActivityLocked(ActivityRecord prev) { |
③这里,mResumedActivity = null,不走暂停流程。
④next.app != null &&next.app.thread != null 为 true,调用 ApplicationThead.scheduleResumeActivity(),到客户进程恢复指定 Activity。
⑤经过消息传递,调用 ActivityTHread.handleResumeActivity()
⑥调用 ActivityTHread.performResumeActivity() 正在恢复 Activity,接着回调 Activity 的 onResume() 方法。
4 stop 停止 Activity
前面几节汇总,A 启动到 B 时,需要先暂停 A,然后再启动 B。什么时候停止(stop) 或者销毁(Destory) 呢?
4.1 从暂停到停止全过程
4 按 Home 键回到桌面
5 按 Back 键回到上一个 Activity
6 长按 Home 键
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论