ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Android Activity启动流程全解析:从startActivity到onResume的完整链路

Android Activity启动流程全解析:从startActivity到onResume的完整链路 做 Android 开发这几年我一直觉得能把 Activity 启动过程讲清楚的人才算真正摸到了 Framework 的门槛。面试的时候Activity 启动流程几乎是必考题但大多数人背了一堆时序图真到排查问题的时候依然一头雾水。我自己也是踩了不少坑、翻了不少源码之后才慢慢建立起完整的认知今天就把这条链路从头到尾拆开揉碎了讲一遍。这篇文章不打算只贴一堆源码片段然后草草收场而是会按照实际的调用顺序把客户端发起请求、系统服务调度、回到应用进程执行生命周期这一整条路径都梳理清楚。适合正在准备进阶面试的开发者、遇到启动异常无从下手的调试人员以及所有对系统源码有好奇心、想弄懂底层原理的人。1. 源码解析这趟路该怎么读才不迷路1.1 先建立整体流程地图很多初学者读源码最大的问题就是一头扎进某个方法里出不来。看ActivityStarter的时候觉得逻辑好多看ActivityTaskManagerService的时候又觉得状态机复杂到爆炸最后看了几天源码脑子里只剩一团乱麻。我从第一次啃这块源码到现在总结出一个经验源码阅读必须先有地图再谈细节。没错你得先知道整条链路分几段每一段的起点和终点在哪里然后再逐个击破。Activity 启动这条链路宏观上就是三件事应用进程通过 Binder 调用系统服务发起启动请求。系统服务system_server 进程中的 ActivityTaskManagerService完成一系列校验、状态判断和调度决定 Activity 应该以什么方式启动并处理好任务栈。系统服务把执行指令通过 Binder 回传给应用进程应用进程在主线程消息循环里执行真正的生命周期回调。这三件事分别发生在两个进程里中间隔着两次跨进程通信。理解这一点特别重要因为很多人把整个流程当成单进程的调用链去理解结果怎么都对不上。实际上startActivity这个方法的执行是异步的调用方发出请求之后并不会阻塞等待结果所有流程都是通过 Messenger、Binder 加消息循环这套机制联动起来的。有了这张地图再看源码就不会迷路。下面的每个章节都会对应地图中的一段我们一段一段来串。1.2 三处关键代码入口client、system_server、client我在给团队做技术分享的时候特别喜欢强调一个观点Activity 启动流程不是一条直线更准确地说是一个环。你从应用进程出发经过系统服务最后还会绕回应用进程。理解这个环形结构比记住某一处代码更有价值。第一处入口在应用进程。当我们调用startActivity(Intent)的时候实际进入的是ContextImpl.startActivity()它会经过Instrumentation.execStartActivity()在这里完成对 ActivityManager 服务的 Binder 调用。这第一段代码的目标非常明确把启动请求打包并通过 Binder 送出去。第二处入口在 system_server 进程。ActivityTaskManagerService.startActivity()收到请求后会通过ActivityStarter做一系列决策比如 Activity 是否存在、有没有权限、要放入哪个任务栈、是否需要创建新的 task、退场动画怎么做等。这一段的逻辑是全流程中最复杂的因为设计到窗口、任务、栈、进程多方面的调度。第三处入口又回到了应用进程。系统服务决策完成后需要通过IApplicationThread接口回调应用进程。老版本的 Android 会直接调用scheduleLaunchActivity()新版本则引入了ClientTransaction事务机制统一封装了启动 Activity 和生命周期状态的变更由TransactionExecutor负责逐项执行。应用进程收到回调后通过主线程 Handler 切换到 UI 线程最终执行ActivityThread里的handleLaunchActivity()走到Activity.onCreate()/onStart()/onResume()。如果你能把这三次逻辑跳跃印在脑子里剩下的所有代码细节都可以被归类到这三个阶段里的某一处。读源码的效率会翻倍面试被问到的时候思路也会顺畅很多。2. 启动链路核心类拆解从 startActivity 到 ATMS2.1 客户端入口ContextImpl 和 Instrumentation平时我们调用startActivity()其实只是站在了一长串代码的最顶端。Activity和ContextWrapper里的startActivity最终都会委托给ContextImpl。为什么不是直接交给Activity自己处理因为ContextImpl是 Context 的真正实现类它不依赖于具体组件任何有 Context 的地方比如Service、Application都可以用它来发起跳转。我们看一下ContextImpl.startActivity()的关键路径Override public void startActivity(Intent intent, Bundle options) { warnIfCallingFromSystemProcess(); ... if ((intent.getFlags() Intent.FLAG_ACTIVITY_NEW_TASK) 0 options ! null ActivityOptions.fromBundle(options).getLaunchDisplayId() ! INVALID_DISPLAY mDisplay ! null) { // 处理多屏相关 ... } final ActivityThread mainThread mMainThread; ... if (mActivityTaskManager ! null) { ... } final int result ActivityTaskManager.getService().startActivity( mMainThread.getApplicationThread(), getOpPackageName(), intent, ...); ... }注意这里的ActivityTaskManager.getService()。在现代 Android 版本里Activity 的调度职责已经从ActivityManagerService拆分到了ActivityTaskManagerService简称 ATMS单看ActivityManagerService你会发现它只负责进程和内存管理了。这是一个很重要的架构演进面试的时候能讲清楚会非常加分。Instrumentation.execStartActivity()则在ContextImpl之前拦截了一步。Instrumentation是系统用来监控应用运行状态的工具类测试框架、性能监控、启动耗时统计都会依赖它。它在这里做的事情是把启动请求包装好调用 ATMS并在调用出错时统一抛出异常比如常见的ActivityNotFoundException。有一个小细节值得注意如果启动方向传了Bundle options里面通常包含启动动画、窗口模式、共享元素等参数。系统会把这些参数解析成ActivityOptions对象最终传递给ActivityStarter。后面我们讲动画设置的时候还会再提到。2.2 跨进服务的门ActivityTaskManager.getService()跨进程通信是理解 Android Framework 的一大难点但我建议从使用角度先记住结论ActivityTaskManager.getService()返回的是一个 Binder 代理对象通过它可以直接调用 system_server 进程里的 ATMS 方法。代码层面IActivityTaskManager是一个接口它的实现类ActivityTaskManagerService运行在 system_server 进程中。调用方的getService()拿到的是一个ActivityTaskManagerProxy这是典型的 Binder 代理模式public static IActivityTaskManager getService() { return IActivityTaskManagerSingleton.get(); }IActivityTaskManagerSingleton内部通过ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE)拿到底层 Binder再通过asInterface转换成IActivityTaskManager。这个模式在 Android 里到处都是PackageManager、WindowManager、AlarmManager全都长这样看多了就会有一种天下 Binder 一大抄的感觉。到了ActivityTaskManagerService.startActivity()其实真正的实现也不会堆在这里。它会快速转发给ActivityStartController.obtainStarter()用一个建造者模式构造ActivityStarter然后执行execute()。这句代码是整条链路里第一个真正的逻辑分叉点因为从这里开始启动请求就进入了系统侧的任务栈调度逻辑。2.3 服务端调度ActivityStarter 和 ActivityStackSupervisorActivityStarter是整个启动流程里面代码量最大、分支最多的类之一它的executeRequest()方法就是名副其实的决策室。它会做这些事情从 Intent 里解析出ActivityInfo也就是目标 Activity 的清单信息如果解析不到就直接抛异常兜底。计算启动标志和启动模式standard、singleTop、singleTask、singleInstance结合 Intent flags 和 manifest 配置确定最终的启动方式。与ActivityStackSupervisor协作找到合适的任务栈Task。比如singleTask模式下会复用已有 task并清空它上面的其他 Activity。判断是否需要开启新进程。如果目标 Activity 所在的进程还没创建会调用ProcessList.startProcessLocked()启动新进程。我见过很多开发者卡在这一步理解不了因为他们总觉得启动一个 Activity就是创建一个对象。实际上创建 Activity 对象、创建进程、创建任务栈是三件独立的事。系统会先决定 Activity 该放哪再决定进程是否需要拉起最后才会考虑在应用进程里反射出 Activity 实例并回调生命周期。ActivityStackSupervisor的逻辑同样值得关注。它内部管理了mRootWindowContainer、mRecentTasks、mActivityMetricsLogger等等负责 Activity 窗口层级和返回栈的调度。启动流程走到这里时ActivityStarter已经基本完成了任务接下来就要把舞台交给ActivityStackSupervisor去处理谁上前台的问题也就是resumeTopActivity的逻辑。如果是第一次启动应用这一步还会触发冷启动链路涉及ProcessList创建进程、ActivityThread.main()入口、attach()回绑系统服务。这段内容比较多我们留到第三节再说。2.4 动画与 Uri 传递ActivityOptions 与 content:// 的注意点开发中经常会遇到Activity切换动画失效、共享元素不起作用的问题根源多半就是对ActivityOptions不够熟悉。ActivityTaskManagerService.startActivity()的入参里Bundle options最终会转化成ActivityOptions里面携带了启动的动画资源 ID 或者自定义动画对象。常见的设置动画方式Intent intent new Intent(this, SecondActivity.class); Bundle options ActivityOptions.makeCustomAnimation( this, R.anim.slide_in_right, R.anim.slide_out_left).toBundle(); startActivity(intent, options);如果你在启动时没有传 options系统会使用主题里定义的windowAnimationStyle。有时候换了主题但动画没生效问题往往出在主题父类或者windowAnimationStyle被覆盖了。我在实际排查中遇到过一个情况同一个页面用普通方式打开有动画用PendingIntent方式打开就没动画因为PendingIntent的创建需要显式传入ActivityOptions否则系统会采用默认的淡入淡出或者完全无动画模式。另外要说一下content://这类 Uri 传递。你在Intent里携带 FileProvider 生成的 Uri 时除了要配置grantUriPermission还应该明确添加访问权限的 flagintent.setData(uri); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);跨应用跳转时如果没有这一步目标应用读取 Uri 极有可能抛出SecurityException或者FileNotFoundException。源码层面看系统在ActivityStarter里会检查Intent的 flags 和 grant 状态提前校验是否有权限访问该 Uri。这也是为什么很多人用FileProvider.getUriForFile()生成了合法的 Uri对方应用还是读不到文件的原因——你只在 manifest 里加了 provider 配置却忘了在跳转时显式授权。3. 回到应用进程事务机制和生命周期回调全流程3.1 ClientTransaction 与执行器现代版本的事务设计Android 10API 29之后系统侧回调应用进程的机制有了很大变化。早期版本是直接调用IApplicationThread.scheduleLaunchActivity()一个方法负责一件事。后来引入了ClientTransaction的概念把启动一个 Activity和执行一系列生命周期状态变更统一封装成一条事务然后由系统侧的一次 Binder 调用发送给应用进程。这个设计的价值在于统一和可扩展。比如启动 Activity 的同时系统可能还想让前一个 Activity 进入onPause或onStop状态这些变化在旧版本里分散在多个回调中时序容易出现偏差。现在它们都被打包进同一条事务里应用进程端只需按顺序执行即可。看关键的几个类ClientTransaction封装了事务的内容包括一个 callback比如LaunchActivityItem和一系列ActivityLifecycleItem比如PauseActivityItem、ResumeActivityItem。ClientTransactionHandler应用进程端的处理接口ActivityThread实现了它。TransactionExecutor负责真正执行事务里的所有内容决定执行顺序并驱动事务执行。TransactionExecutor.execute()的逻辑核心是两层循环先执行 callback也就是创建 Activity 再执行 lifecycleItem让它按顺序经历生命周期状态。public void execute(ClientTransaction transaction) { ... executeCallbacks(transaction); executeLifecycleState(transaction); ... }一句话总结启动 Activity 是事务的第一步后续的onStart、onResume是事务的后续状态更新。它们在同一趟携带过程中被送往应用进程再由应用进程在指定线程上逐项执行。3.2 ActivityThread 怎么处理客户端事务应用进程的主入口是ActivityThread.main()。它内部有一个名为H的内部 Handler负责处理来自系统服务的各种消息。H的handleMessage()方法里有一类消息专门对应EXECUTE_TRANSACTION也就是执行客户端事务。ActivityThread实现ClientTransactionHandler接口后在handleMessage的分支里会拿到ClientTransaction对象并调用TransactionExecutor.execute()。于是从 Binder 回调到主线程消息队列再到最终执行这是一条完整的事件流。在主线程里执行启动保证了 UI 操作不会因为线程问题崩掉。但也正因为所有生命周期回调都发生在主线程一个耗时操作就可能导致后续的 Activity 无法及时启动这也是为什么会派生出一系列启动优化方案。源码里你能看到大量traceBegin/traceEnd埋点官方工具Systrace和Perfetto能分析启动耗时的每一步原理就是读取这些 trace 标记。3.3 生命周期时序onCreate → onStart → onResume 的调用真相生命周期回调的顺序在TransactionExecutor执行LaunchActivityItem.execute()和随后的ResumeActivityItem.execute()时就已经基本确定了。先看LaunchActivityItem.execute()Override public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { client.handleLaunchActivity(r, pendingActions, null /* customIntent */); }handleLaunchActivity()内部会调用performLaunchActivity()这一步做了非常核心的事情通过LoadedApk获取 ClassLoaderClass.forName(className)反射创建 Activity 实例。创建Application如果还没创建并调用application.attach(context)。调用activity.attach()在这里完成Window、WindowManager等 UI 基础设施的绑定。回调activity.onCreate()这会读取ActivityInfo里配置的theme并调用setContentView。接着回调activity.onStart()。随后TransactionExecutor继续执行ResumeActivityItem走到handleResumeActivity()通过performResumeActivity()回调activity.onResume()并真正把DecorView交给WindowManager去添加渲染。这里有个值得留意的细节屏幕上的真正显示其实发生在onResume之后的WindowManager.addView()流程里。所以很多人以为onResume执行完画面就已经显示了严格来说这个说法不够准确。onResume只是系统层面的正确时点真正出帧还得看ViewRootImpl的绘制调度和硬件渲染的配合。3.4 一个真实的启动时序对比表为了帮助理解我整理一个简化版的时序表把它当成面试回答的提纲也非常好用阶段关键方法所在进程行为说明请求发起ContextImpl.startActivityApp封装 Intent准备 Binder 调用请求转发Instrumentation.execStartActivityApp监听并转发请求拦截异常系统服务入口ActivityTaskManagerService.startActivitySystem接收请求分发到 ActivityStarter启动决策ActivityStarter.executeSystem解析 ActivityInfo确定任务栈任务栈调度ActivityStackSupervisor.resumeTopActivitySystem决定前台 Activity 和窗口层级事务下发ClientLifecycleManager.scheduleTransactionSystem封装 ClientTransactionBinder 回传主线程处理ActivityThread.HApp收到消息切到 UI 线程执行事务TransactionExecutor.executeApp按序执行 Launch 和 Resume创建 ActivityActivityThread.performLaunchActivityApp反射创建attach 窗口回调 onCreate显示渲染WindowManager.addViewApp真正的窗口添加和 ViewRootImpl 绘制这张表串起来就是一条比较完整的链路了。如果再往下追问每一行都可以继续展开成一篇独立的源码分析但对日常开发和面试来说能把这张表讲透很多问题已经可以答得很有体系了。4. 常见异常与排查思路从源码角度找问题4.1 找不到 Activity 和 Uri 授权问题先看一种很常见的崩溃android.content.ActivityNotFoundException: No Activity found to handle Intent这个错误的信息虽然直白但背后的原因可能有很多种。从源码角度看ActivityStarter在启动时会调用ActivityInfo的解析逻辑通过PackageManager匹配 Intent 的 action、data、category。如果匹配不到任何组件就会直接抛异常。排查思路一般是先看目标 Activity 有没有在 manifest 里注册再看 intent 的 action 是否准确最后确认setPackage()有没有设置目标包名。跨应用跳转时如果两个应用的签名不同还可能需要配置android:exportedtrue这个属性在 Android 12 之后变得尤为严格漏配就是崩溃一点都不留情面。还有的同学会碰到ClassNotFoundException或者 Activity class does not exist 这类报错。这种情况下目标 Activity 类名往往被混淆了或者模块冲突导致类被裁掉了。排查时我会先打开 build 产物里的 mapping 文件确认混淆后类名到底变成什么再看 APK 里classes.dex是否真的包含这个类。前面提到的content://Uri 授权问题也是启动时特别容易踩的坑。最常见的报错是SecurityException原话大概长这样 Permission Denial: reading com.xxx.FileProvider uri from pid..., uid... requires the provider be exported, or grantUriPermission()。问题根源在于系统在跨进程传递数据时对content://Uri 有严格授权校验。你在进程 A 通过 FileProvider 生成了一个 Uri想让进程 B 读取必须要在 Intent 上显式加上FLAG_GRANT_READ_URI_PERMISSION或者通过clipData的方式一并授权。如果还是读不到就得确认 FileProvider 的paths配置是否正确缓存目录、外部私有目录每类路径都要对号入座。4.2 生命周期乱序、二次回调第二种典型问题是明明是第一次启动 ActivityonCreate却被调用了两次或者跳转 A 到 B 时A 的onStop迟迟不来导致页面一直闪烁或者出现任务切换的视觉效果。从生命周期源头看这些乱序问题大多发生在ClientTransaction执行阶段。比如键盘弹起、窗口焦点变化、配置变更都会触发额外的 activity relaunch 或者 configuration change这些都会走一遍 display 流程导致onDestroy和重新onCreate。如果你在onSaveInstanceState里漏了状态保存就会看到数据丢失的坑。还有一个细节问题值得留意当 A 启动 B 后A 的onPause会立即执行但onStop的执行时机取决于窗口是否完全不可见。如果 B 的启动动画还没有结束A 的窗口可能仍然可见Finalizer 就不会触发onStop。很多开发者在这个地方容易焦虑其实不是生命周期乱序而是窗口层面的可见性判断逻辑没走完。遇到这类问题我一般会先用adb shell dumpsys activity activities查看 ActivityRecord 的状态机确认各个 Activity 处于什么 state。再结合 Trace 文件看TransactionExecutor的执行轨迹基本上半小时内能定位个大概。4.3 启动慢和 ANR 的排查参考启动慢是一个非常综合的问题从源码角度拆解可以分成几个阶段去测Application.attach/attachBaseContext阶段如果是冷启动Application 对象的创建和onCreate会阻塞主线程任何在这个阶段的耗时都会直接影响启动速度。Activity.onCreate/onStart布局填充、数据初始化、第一次网络请求这三座大山是启动耗时的主要来源。onResume之后的首帧渲染ViewRootImpl初次绘制、Choreographer注册 frame callback、Measure/Layout/Draw三步曲都会影响首帧显示。启动如果卡到 ANR最常见的原因就是onCreate里执行了重度同步任务比如大的数据库查询、IO 读写、网络同步。ANR 的底层原理其实就是在主线程消息队列里埋了一个超时消息如果在规定时间内没被移除系统就判定为 ANR。读源码时能看到AppNotRespondingDialog的触发链路它在ProcessRecord的appNotResponding()里。排查启动 ANR 我有几个稳定的小技巧用adb shell am start -W package/activity输出启动耗时曲线关注TotalTime和WaitTime。抓一份 ANR trace用Android Studio的APK Analyzer或者Perfetto打开看主线程卡在哪。如果主线程卡在Binder调用上还要看是不是系统服务太忙比如PackageManager的并发查询导致长时间持锁。4.4 从源码角度看冷启动优化最后聊点实在的冷启动优化方向。我们平时说的冷启动优化本质上是跟源码里的这条链路抢时间核心思路无外乎以下四个方向减少 Application 初始化耗时。把不必要的懒加载都挪到onCreate之后或者拆到子线程。很多人会在 Application 里初始化一堆 SDK实际很多 SDK 支持子线程初始化或者延迟初始化硬塞在主线程里等于在源码的handleCreateApplication()阶段白白浪费时间。布局优化。减少嵌套层级用ConstraintLayout或merge标签合并布局。源码级别来说onCreate里setContentView的耗时直接决定了performLaunchActivity的时间所以这块优化收益来得最直观业界现在也有不少X2C或者LayoutInflater.Factory2替换方案来缩短 inflate 时间。异步起线程。启动阶段如果非做耗时任务不可建议把任务交给子线程并通过Handler回到主线程做 UI 更新。这里需要特别注意不要让 App 提前进入onResume再回来改 UI避免造成不必要的重绘。使用启动器框架。像常见的启动器框架如AnchorTask、Alpha等本质上都是对onCreate阶段的 task 进行拓扑排序把能并行的任务并行化把有依赖的任务按顺序执行。理解了源码里Application到Activity.onCreate的整个过程你就知道这种框架到底优化了哪个时间段。我自己在实际项目里做过一个对比一个冷启动时间原本在 2.8 秒左右的应用通过拆分 Application 初始化、游戏化首帧渲染、减少首屏布局嵌套最终降到了 1.3 秒左右提升还是很明显的。启动优化不是一味地堆代码而是要知道系统在哪几个关键节点安排了什么工作你才能见缝插针。5. 高级技巧从源码到实际开发的延伸5.1 利用 ActivityLifecycleCallbacks 做全局监控理解了生命周期回调的来源之后你就可以用一个非常简单的工具做到全局状态监听那就是Application.ActivityLifecycleCallbacks。它的原理其实是ActivityThread在每次执行生命周期回调的时候会同步通知所有注册过的 callbacks因此我们可以在不侵入任何一个 Activity 的情况下统一处理以下场景统计每个页面的停留时长判断是否进入后台。在onActivityCreated时记录启动耗时埋点。在onActivityDestroyed时做资源释放兜底。这个工具用起来简单但理解原理之后再去看它的文档你会明显感觉自己能掌控它而不是只会调用接口。比如我后来排查过一个问题某个 Activity 的onDestroy被调用了但isFinishing()却返回 false最后发现是因为 Activity 被系统强行回收而LifecycleRegistry的同步没有走到 onDestroy 的标记逻辑这种问题不看源码根本猜不到。5.2 Activity 动画设置的几个实战参数前面提到ActivityOptions这里再补充几个实战中经常配置的参数尤其是针对需要自定义转场动画的场景// 1. 自定义进入/退出动画 Bundle options ActivityOptions.makeCustomAnimation( context, R.anim.slide_in_right, R.anim.slide_out_left).toBundle(); // 2. 打开新页面时让页面以缩放形式进入 Bundle options ActivityOptions.makeScaleUpAnimation( sourceView, startX, startY, startWidth, startHeight).toBundle(); // 3. 共享元素转场 Bundle options ActivityOptions.makeSceneTransitionAnimation( activity, sharedView, shared_element_name).toBundle();共享元素动画在源码里要经过ActivityOptions解析、RemoteTransition注册、Transition协调等步骤跨进程通信时会有额外的时间开销所以动画有掉帧或者延迟感不一定是你代码问题也有可能是系统在等下一帧的 choreographer 信号。调优时留意过渡期间不要做重的onResume逻辑即可。5.3 从启动流程看多进程架构再来扯一下多进程开发的灵感。很多人看源码到 system_server 那一段时都会惊叹它的架构设计一个核心服务一群通过 Binder 连接的应用进程。这套架构放到应用开发里其实也通用比如音视频播放器中我们可以把一个播放器核心放到独立进程UI 进程和播放器进程通过AIDL通信这样即使播放进程崩了UI 也不会被拖垮。Activity 启动源码背后那种服务拆分、状态机驱动、事务化通信的思路完全可以借鉴到大型应用的模块解耦上。一个典型例子是把扫码、地图、推送这些模块拆成独立服务通过统一接口和路由层调度而不是让所有业务都挤在单进程里。理解了系统侧的ClientTransaction封装后你在设计自己的跨进程通信协议时也会更加注重事务的一致性和顺序性。5.4 面试答题的梳理提示关于面试不少同学纠结要不要把源码细节全部背下来。我的建议是不用背但要能把链路讲顺并且能围绕几个关键点展开。常见的追问有以下几种Intent 里带一个自定义 Object 为什么不能直接传递因为Binder传输的是 Parcelable你要么序列化要么走全局静态不推荐。Activity A 启动 BA 和 B 的onPause/onStop/onCreate顺序是怎样的这个要看是同一个进程还是不同进程。同一进程里通常是 A.onPause → B.onCreate → B.onStart → B.onResume → A.onStop不同进程时由于 binder 调度和进程启动的并行时序可能略有偏差。为什么要用TransactionExecutor而不是多个scheduleXxx因为事务可以保证一批操作原子性和顺序性避免生命周期乱序。冷启动为什么慢可以回答主要时间消耗在进程创建、Application 初始化、Activity 创建和首帧渲染四个环节再逐一展开。面试官往往看重的不只是你说出多少类名和方法名而是你能否把为什么要这样设计解释清楚。有源码打底讲出来会比背书生动得多。6. 结尾一点个人体会Activity 启动源码我前前后后读过很多遍每次读都会发现新的细节。刚开始只是想知道一个 Activity 到底是怎么创建出来的后来慢慢在里面看到了系统对自己内部架构的反思和演进。从早期的方法直调到现在的ClientTransaction事务机制Android 团队的设计思路也在持续变化这对我们写业务代码其实非常有启发。对于想深入源码的同学我给的建议是从一条最简单的链路开始遇到不懂的类就查官方文档再对照手机上的dumpsys输出一点点磨。不要追求一下子就懂所有细节能把主链路讲清楚就是很大的进步了。等你把 Activity 启动流程吃透了再去看Service的绑定流程、ContentProvider的初始化流程你就会发现它们之间有不少相似的地方整个 Android Framework 的代码就不再是一个黑盒了。希望这篇分享能帮你跨过那道坎真正啃下这块硬骨头。
返回列表