简介
为什么要学习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