Android之Activity启动流程

667 阅读10分钟

简介

为什么要学习Android的源码

  1. 学习优秀的代码,可能是进步最快的方式之一,特别是看一群优秀的Google开发工程师的代码。
  2. 知己知彼,了解系统的运行原理。在实际的项目开发中,解决一些疑难杂症,对于排障分析有很重要的意义。(开发中最怕就是特殊机型兼容,一些无日志的问题,这个时候只能靠经验来分析,熟悉系统的运行流程就显得很重要)
  3. 不要做一个只会堆砌API的工程师,否则无论3年或者5年,你始终会感觉到瓶颈的到来。其实换个角度学Android,例如源码分析、性能优化。你可能可以看到不一样的世界。

什么是Activity的启动流程

很多童鞋可能想,这还不简单,项目中用了千千万万遍了

startActivity(new Intent(this, Activity.class));

只能说Too young,Too simple。

我一开始也以为只是简单调用个startActivity,然后屏幕就跳转到指定的Activity,这就是Activity的启动流程。

我们都知道Activity有一个栈,当我们按了back键的时候,就会回到上一个Activity。那么系统是如何来管理这个栈的呢?

我们从launcher点击一个应用图标,那么会启动一个新的进程,系统如何控制多进程之间的Activity切换呢?

我们都知道Activity有它自己的生命周期,那么这个生命周期在运行的过程中,系统是怎么去做控制的呢?

实际上问题远远不止这些,可见Activity的启动流程不是想象中的那么简单,所以为了找寻真相,我们需要从Android的源码来分析Activity的启动流程。

Activity基础

这里我们先简单来了解一些我们开发项目过程中,常用的一些Activity的基础知识,然后后续才来进行源码的分析。在源码的分析中,我们也可以结合日常的使用来结合分析。

生命周期

这里使用Google官方的示例图来说明

Google官方示例图

  • Activity 的整个生命周期发生在 onCreate() 调用与 onDestroy() 调用之间。您的 Activity 应在 onCreate() 中执行“全局”状态设置(例如定义布局),并释放 onDestroy() 中的所有其余资源。例如,如果您的 Activity 有一个在后台运行的线程,用于从网络上下载数据,它可能会在 onCreate() 中创建该线程,然后在 onDestroy() 中停止该线程。

  • Activity 的可见生命周期发生在 onStart() 调用与 onStop() 调用之间。在这段时间,用户可以在屏幕上看到 Activity 并与其交互。 例如,当一个新 Activity 启动,并且此 Activity 不再可见时,系统会调用 onStop()。您可以在调用这两个方法之间保留向用户显示 Activity 所需的资源。 例如,您可以在 onStart() 中注册一个 BroadcastReceiver 以监控影响 UI 的变化,并在用户无法再看到您显示的内容时在 onStop() 中将其取消注册。在 Activity 的整个生命周期,当 Activity 在对用户可见和隐藏两种状态中交替变化时,系统可能会多次调用 onStart() 和 onStop()。

  • Activity 的前台生命周期发生在 onResume() 调用与 onPause() 调用之间。在这段时间,Activity 位于屏幕上的所有其他 Activity 之前,并具有用户输入焦点。 Activity 可频繁转入和转出前台 — 例如,当设备转入休眠状态或出现对话框时,系统会调用 onPause()。 由于此状态可能经常发生转变,因此这两个方法中应采用适度轻量级的代码,以避免因转变速度慢而让用户等待。

启动模式

  • standard(默认模式)

默认。系统在启动 Activity 的任务中创建 Activity 的新实例并向其传送 Intent。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例。

  • singleTop

如果当前任务的顶部已存在 Activity 的一个实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建 Activity 的新实例。

  • singleTask

系统创建新任务并实例化位于新任务底部的 Activity。但是,如果该 Activity 的一个实例已存在于一个单独的任务中,则系统会通过调用现有实例的 onNewIntent() 方法向其传送 Intent,而不是创建新实例。

  • singleInstance

与 "singleTask" 相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。该 Activity 始终是其任务唯一仅有的成员;由此 Activity 启动的任何 Activity 均在单独的任务中打开。

运行状态保存

这里同样借助Google官方的示例图来说明

Google官方示例图

这个运行状态的保存,往往很容易在开发中被遗忘。如果不注意,却很容易引起一些程序的异常。首先,系统的运行的中,如果内存不足,会回收一些资源。再者,一些ROM会开启例如开发中选项中的不保留活动,当应用到后台时,则会被回收,或者屏幕旋转等一些配置变更。这些情况都需要我们处理好运行状态的保存。例如Viewpager保存好当前的tab位置,一些数据的保存和恢复,避免空指针等。

在界面被回收时,系统会先调用 onSaveInstanceState(),然后再使 Activity 变得易于销毁。系统会向该方法传递一个 Bundle,您可以在其中使用 putString() 和 putInt() 等方法以名称-值对形式保存有关 Activity 状态的信息。然后,如果系统终止您的应用进程,并且用户返回您的 Activity,则系统会重建该 Activity,并将 Bundle 同时传递给 onCreate() 和 onRestoreInstanceState()。您可以使用上述任一方法从 Bundle 提取您保存的状态并恢复该 Activity 状态。如果没有状态信息需要恢复,则传递给您的 Bundle 是空值

源码相关类介绍

过完了Activity的基础知识后,我们通过一个表格来分析一下Activity启动流程中核心的一些类的设计及作用,这样可以让我们更好的来了解启动的流程。

类名 主要作用
Activity Activity 是一个应用组件,用户可与其提供的屏幕进行交互。
Instrumentation 每一个应用程序只有一个Instrumentation对象,每个Activity内都有一个对该对象的引用。当ActivityThread需要操作Activity的生命周期,都是通过Instrumentation来完成,实际Activity的实例化,也是在里面的newActivity完成。
ActivityManagerService AMS(ActivityManagerService)是贯穿Android系统组件的核心服务,负责了系统中四大组件的启动、切换、调度以及应用进程管理和调度工作
PackageManagerService Android系统下的apk程序都是通过名为PackageManagerService的包管理服务来管理的。PacketManagerService是安卓系统的一个重要服务,由SystemServer启动,主要实现apk程序包的解析,安装,更新,移动,卸载等服务。不管是系统apk(/system/app),还是我们手工安装上去的,系统所有的apk都是由其管理
ActivityStackSupervisor 主要是对整个APP的Task进行管理,通常一个进程拥有一个或多个Task
ActivityStack 传说中的Activity栈,我们都知道Activity的管理就是通过栈管理,默认显示栈顶,当按back键后,就将栈顶的Activity移除,遵循后进先去原则
ActivityRecord ActivityRecord 是Activity的标识,与每个Activity是一一对应的,存储这Activity的一些信息,便于后续操作Activity
ActivityThread 传说中的UI线程, 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口)负责调度和执行activities、broadcasts和其它操作

源码启动流程分析

Activity的源码启动流程,其实一开始想试试用流程图来说明,但最后发现实在太长,欲生欲死。下面我们同样通过表格,以序号的方式来一步步显示Activity启动流程。这个可以更清晰便捷的来理解。具体的关键实现源码会在说明中分析,可以自己在结合源码进行分析。

索引 调用的类间关系 说明
1 Activity:startActivity->startActivityForResult startActivity其实最终也是调用了startActivityForResult
2 Intrumentation:execStartActivity mInstrumentation类似与管家婆,ActivityThread与AMS交互后,最后都是交由Intrumentation来处理
3 ActivityManagerNative.getDefault().startActivity(AIDL)->最后执行到AMS的startActivity 这是一个IPC的过程
4 AMS:startActivityAsUser 生成了userId
5 ActivityStackSupervisor:startActivityMyWait() 校验Intent的一些合法性,其中调用了PackageManagerService的resolveIntent
6 ActivityStackSupervisor:startActivityLocked() 验证intent、Class、Permission等保存将要启动的Activity的Record
7 ActivityStackSupervisor:startActivityUncheckedLocked() 检查将要启动的Activity的launchMode和启动Flag根据launcheMode和Flag配置task
8 ActvityStack:startActivityLocked 对栈进行初始化配置
9 ActivityStack: resumeTopActivityInnerLocked() 查找需要进入onPause的Activity
10 ActivityStack:startPausingLocked() IPC,控制将需要OnPause的Activity进行暂停
11 ActivityThread: handlePauseActivity() 回调Activity的onPause,并通知AMS
12 ActivityManagerService:activityPaused() 获取对应的栈,执行activityPausedLocked
13 ActivityStack:activityPausedLocked 获取ActivityRecord,调用completePauseLocked
14 ActivityStackSuperVisor: resumeTopActivitiesLocked() 找出当前自己管理的task的栈,执行resumeTopActivityLocked
15 ActivityStack:resumeTopActivityLocked() 调用ActivityStackSuperVisor:resumeTopActivityInnerLocked验证是否该启动的Activity所在进程和app是否存在,若存在,直接启动。否则,准备创建该进程
16 ActivityStackSuperVisor:startSpecificActivityLocked() 该进程不存在,创建进程
17 ActivityManagerService:startProcessLocked() 通过Process.start()启动进程 entryPoint = "android.app.ActivityThread"
18 ActivityThread:main() 主线程的Looper也在这里初始化,这里是我们应用层的主入口。
19 ActivityThread:attach 调用attachApplication()
20 IActivityManager:attachApplication() 调用attachApplicationLocked,我们的Application也会在这个地方来创建
21 ActivityStackSuperVisor:attachApplicationLocked() 通过ActivityRecord找出具体的栈
22 ActivityStackSuperVisor:realStartActivityLocked() IPC通知ActivityThread
23 ActivityThread:scheduleLaunchActivity() 通过handler调用handleLaunchActivity,接着performLaunchActivity
24 ActivityThread:接着performLaunchActivity 进行了一些Avcitity的状态判断,执行了mInstrumentation.newActivity。Activity对象真正通过反射实例化出来
25 Intrumentation:callActivityOnCreate 调用了Activity的onCreate

过完一遍,反正欲生欲死了。觉得不是当初想象的那么简单。过源码,我们尽量保持流程性上的理解吧,如果纠结于实现的细节,反倒会适得其反,不可自拔。通过流程上的梳理,来理解设计的精髓。

总结

  1. Android源码中大量使用了Service的思想。提供统一的服务,这样使得系统可以统一来调用一些任务。为什么这里的Activity启动要设计得如此的复杂?因为系统需要统一管理窗口的显示,这里涉及多进程、多窗口的管理控制。
  2. 单一责任原则。这个是设计模式里面的东西。不同的功能让不同的类来实现,减低耦合性。例如这里的ActivityStackSupervisor用来管理Task,ActivityStack用来管理栈。而不会将所有的东西都塞在Activity中
  3. 模块化思想。系统的各种Service其实很好的体现了这一点。AMS管理Activity,WMS管理窗口,PMS管理安装包,还有例如网络、电量等的管理都一致。这样使得系统逻辑更加清晰,便于维护管理及使用

关于

欢迎关注我的个人公众号

微信搜索:一码一浮生,或者搜索公众号ID:life2code

image