简介
为什么要学习Android的源码
- 学习优秀的代码,可能是进步最快的方式之一,特别是看一群优秀的Google开发工程师的代码。
- 知己知彼,了解系统的运行原理。在实际的项目开发中,解决一些疑难杂症,对于排障分析有很重要的意义。(开发中最怕就是特殊机型兼容,一些无日志的问题,这个时候只能靠经验来分析,熟悉系统的运行流程就显得很重要)
- 不要做一个只会堆砌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官方的示例图来说明
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官方的示例图来说明
这个运行状态的保存,往往很容易在开发中被遗忘。如果不注意,却很容易引起一些程序的异常。首先,系统的运行的中,如果内存不足,会回收一些资源。再者,一些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 |
过完一遍,反正欲生欲死了。觉得不是当初想象的那么简单。过源码,我们尽量保持流程性上的理解吧,如果纠结于实现的细节,反倒会适得其反,不可自拔。通过流程上的梳理,来理解设计的精髓。
总结
- Android源码中大量使用了Service的思想。提供统一的服务,这样使得系统可以统一来调用一些任务。为什么这里的Activity启动要设计得如此的复杂?因为系统需要统一管理窗口的显示,这里涉及多进程、多窗口的管理控制。
- 单一责任原则。这个是设计模式里面的东西。不同的功能让不同的类来实现,减低耦合性。例如这里的ActivityStackSupervisor用来管理Task,ActivityStack用来管理栈。而不会将所有的东西都塞在Activity中
- 模块化思想。系统的各种Service其实很好的体现了这一点。AMS管理Activity,WMS管理窗口,PMS管理安装包,还有例如网络、电量等的管理都一致。这样使得系统逻辑更加清晰,便于维护管理及使用
关于
欢迎关注我的个人公众号
微信搜索:一码一浮生,或者搜索公众号ID:life2code
- 作者:黄俊彬
- 博客:junbin.tech
- GitHub: junbin1011
- 知乎: @JunBin