前言
在日常的开发中,我们通常需要在 Activity / Fragment 的生命周期方法中进行一些繁重的操作,这样使代码看起来十分臃肿。Lifecycle 的引入主要是用来管理和响应 Activity / Fragment 的生命周期的变化,帮助我们编写出更易于组织且通常更加轻量级的代码,让代码变得更易于维护。
Lifecycle 是一个类,它持有 Activity / Fragment 生命周期状态的信息,并允许其它对象观察此状态。
Lifecycle 使用
场景:让 MVP 中的 Presenter 观察 Activity 的 onCreate 和 onDestroy 状态。
- Presenter 继承 LifecycleObserver 接口
1 | interface IPresenter : LifecycleObserver { |
1 | class MyPresenter : IPresenter { |
- 在 Activity 中添加 LifecycleObserver
1 | class MyLifecycleActivity : AppCompatActivity() { |
启动 Activity 会打印:
1 | MyLifecycleActivity: onCreate |
finish Activity 会打印:
1 | MyPresenter: onDestroy |
以上 Presenter 对象只观察了 Activity 的 onCreate 方法和 onDestroy 方法,我们还可以观察其它的生命周期方法。在 Lifecycle 内部有个枚举类 Event , 它包含了 LifecycleObserver 能够观察到的所有生命周期方法,只需要添加上相应的注解即可。
1 | enum class Event { |
Lifecycle 内部还有代表了各个生命周期所处状态的枚举类 State
1 | enum class State { |
在一般开发中,当 Activity 拥有多个 Presenter 并需要在各个生命周期做一些特殊逻辑时,代码可能是:
1 | override fun onStop() { |
这样会使 Activity 的代码变得很臃肿。
如果用 Lifecycle , 只需将持有 Lifecycle 对象的 Activity 的生命周期的响应分发到各个 LifecycleObserver 观察者中即可。
1 | override fun onCreate(savedInstanceState: Bundle?) { |
基本原理
几个概念
LifecycleObserver 接口
Lifecycle 观察者。实现了该接口的类,被 LifecycleOwner 类的 addObserver 方法注册后,通过注解的方式即可观察到 LifecycleOwner 的生命周期方法。
LifecycleOwner 接口
Lifecycle 持有者。实现了该接口的类持有生命周期(Lifecycle 对象),该接口生命周期(Lifecycle 对象)的改变会被其注册的观察者 LifecycleObserver 观察到并触发其对应的事件。
Lifecycle 类
生命周期。和 LifecycleOwner 不同,LifecycleOwner 通过 getLifecycle() 方法获取到内部的 Lifecycle 对象。
State
当前生命周期所处状态。Lifecycle 将 Activity 的生命周期函数对应成 State .
Event
当前生命周期改变对应的事件。State 变化将触发 Event 事件,从而被已注册的 LifecycleObserver 接收。
实现原理
LifecycleOwner
AppCompatActivity 的父类 SupportActivity
和 Fragment
一样,实现了 LifecycleOwner 接口,因此它们都拥有 Lifecycle 对象。
1 | public class SupportActivity extends Activity implements LifecycleOwner, Component { |
1 | public interface LifecycleOwner { |
从源码可知 getLifecycle() 方法返回的是 LifecycleRegistry
对象,而 LifecycleRegistry 是 Lifecycle 的子类,所有对 LifecycleObserver 的操作都是由 LifecycleRegistry 完成的。
LifecycleRegistry
生命周期登记处。作为 Lifecycle 的子类,它的作用是添加观察者、响应生命周期事件和分发生命周期事件。
1 | public class LifecycleRegistry extends Lifecycle { |
根据上面的分析,我们知道 LifecycleRegistry 才是真正替 Lifecycle 去埋头干粗活的类!
接下来继续来看看实现了 LifecycleOwner 接口的 SupportActivity 类是如何将事件分发给 LifecycleRegistry 的。
1 | public class SupportActivity extends Activity implements LifecycleOwner, Component { |
注意到 SupportActivity 的 onCreate() 方法里面有行 ReportFragment.injectIfNeededIn(this)
代码,再进入 ReportFragment 类分析。
ReportFragment
1 | public class ReportFragment extends Fragment { |
不难看出这是一个没有 UI 的后台 Fragment , 一般可以为 Activity 提供一些后台行为。在 ReportFragment 的各个生命周期中都调用了 LifecycleRegistry.handleLifecycleEvent() 方法来分发生命周期事件。
为什么不直接在 SupportActivity 的生命周期函数中给 Lifecycle 分发生命周期事件,而是要加一个 Fragment 呢?
在 ReportFragment 的 injectIfNeededIn() 方法中找到答案:
1 | public static void injectIfNeededIn(Activity activity) { |
有两个原因:为了能让 ProcessLifecycleOwner 正确地工作;②、并非所有的 Activity 都是继承来自 support 包的 FragmentActivity 类的。因此封装一个同样具有生命周期的后台 Fragment 来给 Lifecycle 分发生命周期事件。
另一方面,假如我们不继承自 SupportActivity , 那 Lifecycle 是如何通过 ReportFragment 分发生命周期事件呢?
鼠标停在 ReportFragment 类,同时按下 Ctrl + Shift + Alt + F7
在 Project and Libraries 的范围下搜索 ReportFragment 被引用的地方。我们发现还有 LifecycleDispatcher 和 ProcessLifecycleOwner 两个类有使用到 ReportFragment .
LifecycleDispatcher
生命周期分发者。
1 | class LifecycleDispatcher { |
从源码可知,LifecycleDispatcher 是通过注册 Application.registerActivityLifecycleCallbacks 来监听 Activity 的生命周期回调的。
- 在 onActivityCreated 中添加 ReportFragment , 将 Activity 的生命周期交给 ReportFragment 去分发给 LifecycleRegistry ;
- 在 onActivityStopped() 以及 onActivitySaveInstanceState() 中,将 Activity 及其所有子 Fragment 的 State 置为 CREATED .
ProcessLifecycleOwner
为整个 App 进程提供生命周期的类。
1 | public class ProcessLifecycleOwner implements LifecycleOwner { |
从源码可知:
- ProcessLifecycleOwner 是用来监听 Application 生命周期的,它只会分发一次 ON_CREATE 事件,并不会分发 ON_DESTROY 事件;
- ProcessLifecycleOwner 在 Activity 的 onResume 中调用 Handle.postDelayed() , 在 onPause 中调用了 mHandler.removeCallbacks(mDelayedPauseRunnable) , 是为了处理 Activity 重建时比如横竖屏幕切换时,不会发送事件;
- ProcessLifecycleOwner 一般用来判断应用是在前台还是后台,但由于使用了 Handle.postDelayed() , TIMEOUT_MS = 700,因此这个判断不是即时的,有 700ms 的延迟;
- ProcessLifecycleOwner 与 LifecycleDispatcher 一样,都是通过注册 Application.registerActivityLifecycleCallbacks 来监听 Activity 的生命周期回调,来给每个 Activity 添加 ReportFragment 的。
最后,通过点击 init() 方法,我们发现 LifecycleDispatcher 和 ProcessLifecycleOwner 都是在 ProcessLifecycleOwnerInitializer 类下完成初始化的,而 ProcessLifecycleOwnerInitializer 是一个 ContentProvider .
1 | public class ProcessLifecycleOwnerInitializer extends ContentProvider { |
Lifecycle 会自动在我们的 AndroidManifest.xml 中添加以下代码用于初始化 ProcessLifecycleOwner 与 LifecycleDispatcher , 这样就不需要我们在 Application 中写代码来初始化了。
1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> |
Lifecycle 的最佳实践
- 保持 Activity / Fragment 尽可能的精简,它们不应该试图去获取它们所需的数据,要用 ViewModel 来获取,并观察 LiveData 对象将数据变化反映到视图中;
- 尝试编写数据驱动(data-driven)的 UI , 即 UI 控制器的责任是在数据改变时更新视图或者将用户的操作通知给 ViewModel ;
- 将数据逻辑放到 ViewModel 类中,ViewModel 应该作为 UI 控制器和应用程序其它部分的连接服务。注意:不是由 ViewModel 负责获取数据(例如:从网络获取)。相反,ViewModel 调用相应的组件获取数据,然后将数据获取结果提供给 UI 控制器;
- 使用 Data Binding 来保持视图和 UI 控制器之间的接口干净。这样可以让视图更具声明性,并且尽可能减少在 Activity 和 Fragment 中编写更新代码。如果你喜欢在 Java 中执行该操作,请使用像 Butter Knife 这样的库来避免使用样板代码并进行更好的抽象化;
- 如果 UI 很复杂,可以考虑创建一个 Presenter 类来处理 UI 的修改。虽然通常这样做不是必要的,但可能会让 UI 更容易测试;
- 不要在 ViewModel 中引用 View 或者 Activity 的 context . 因为如果 ViewModel 存活的比 Activity 时间长(在配置更改的情况下),Activity 将会被泄漏并且无法被正确的回收。
参考资料: