前言
大厂面试比较喜欢问,看起来简单,没梳理过就会踩坑的题
问题
- onStart 和 onResume,onPause 和 onStop 从描述上来看差不多,对开发者来说有什么实质性的不同呢?
- 假设当前 Activity 为 A,如果这时用户打开一个新 Activity B,那么 B 的 onResume 和 A 的 onPause 哪个先执行呢?
问题1.
从实际使用过程来说,onStart 和 onResume、onPause 和 onStop 看起来的确差不多,甚至我们可以只保留其中一对,比如只保留 onStart 和 onStop。既然如何,那为什么系统还要提供看起来重复的接口呢?
这两个配对的接口表示的意义不同:
- onStart 和 onStop 从 Activity 是否可见
- onResume 和 onPause 从 Activity 是否位于前台
问题2.
涉及到 Activity 的启动流程,启动流程实际上非常复杂,包含 Instrumentation、ActivityThread 和 ActivityManagerService(经常说的AMS就是它了)。
简述流程:
- 启动
Activity
的请求由Instrumentation
处理,然后它通过 Binder 向 AMS 发送请求 - AMS 内部维护了一个 ActivityStack 并负责栈内的
Activity
的状态同步,AMS 通过ActivityThread
去同步Activity
的状态从而完成生命周期方法的调用
在 ActivityStack
中的 resumeTopActivityInnerLocked
关键代码:
1 | // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity |
从注释里可以看到,在新 Activity 启动之前,栈顶的 Activity 需要先 onPause,新 Activity 才能启动。最终,在 ActivityStackSupervisor 中的 realStartActivityLocked 方法会调用如下代码:
1 | // Schedule transaction. |
ClientTransaction#schedule
方法中的mClient
是一个IApplicationThread
接口,ActivityThread$ApplicationThread
派生这个接口并实现了对应的方法。所以直接到ApplicationThread#scheduleTransaction
方法。ActivityThread
类中没有定义 scheduleTransaction
方法,所以调用的是他父类的 ClientTransactionHandler#scheduleTransaction
方法。
1 | // frameworks/base/core/java/android/app/ActivityThread.java |
在 ClientTransactionHandler#scheduleTransaction 中调用了 sendMessage 方法,该方法是一个抽象方法,实现在 ClientTransactionHandler 的派生类 ActivityThread 中,ActivityThread#sendMessage 方法会把消息发给内部名为H
的Handler
。
1 | // frameworks/base/core/java/android/app/ActivityThread.java |
H 的实例接收到 EXECUTE_TRANSACTION 消息后,调用TransactionExecutor#execute
方法切换 Activity 的状态。TransactionExecutor#execute
方法里先执行 callbacks(如果不为null),然后改变 Activity 当前的生命周期状态。
1 | // frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java |
在executeLifecycleState
方法里:
- 先调用
TransactionExecutor#cycleToPath
方法执行当前生命周期状态之前的状态 - 然后执行
ActivityLifecycleItem#execute
方法,由于是从ON_RESUME
状态到ON_PAUSE
状态切换,中间没有其他状态,cycleToPath 这个情况下没有做什么实质性的事情,直接执行lifecycleItem.execute
方法 - 之前在
ActivityStack.startPausingLocked
方法里面scheduleTransaction
传递的是PauseActivityItem
对象,所以executeLifecycleState
方法里的lifecycleItem
实际是PauseActivityItem
对象
1 | // frameworks/base/core/java/android/app/servertransaction/PauseActivityItem.java |
PauseActivityItem#execute
方法中传入的client
实际上是ActivityThread
对象,所以我们又回到了ActivityThread
。
1 | // frameworks/base/core/java/android/app/ActivityThread.java |
离终点总算不远了,Instrumentation#callActivityOnPause
方法中调用了Activity#performPause
,在performPause
中我们终于看到了熟悉的钩子函数onPause
,至此栈顶Activity
的pause
流程完毕。
总结
这里的源码是根据 Android 9.0 来分析的,跟 5.0 相比,真的复杂了很多,看到一位老哥的 Activity启动流程源码分析写的不错,把 pause 这块的流程分析稍加整理放到了这道题目下,有兴趣的话可以自己翻阅源码。
思考,9.0 的源码里似乎多了很多lifecycle
、状态切换相关的字眼,如果是熟悉aac架构
的老哥们一定不陌生了,9.0 这块改动这么大应该就是加入了 LifeCycle 的特性(确信)。
综上,新启一个Activity
的时候,旧Activity
的onPause
会先执行,然后才会启动新的Activity
。
官网对 onPause 的解释:
The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time the activity is in visible, active and interacting with the user. An activity can frequently go between the resumed and paused states – for example when the device goes to sleep, when an activity result is delivered, when a new intent is delivered – so the code in these methods should be fairly lightweight.
别在 onPause 里做重量级操作,因为 onPause 执行完之后,新 Activity 才能 Resume!