前言
Lifecycle即生命周期,作为Android开发者,我们对生命周期可太熟悉了,因为我们不仅经常在Activity、Fragment的生命周期函数比如onCreate、onResume等中做一些逻辑操作;而且组件的生命周期控制不当的话,可能会导致内存泄漏,或者一些无法预想的结果,比如在后台请求网络操作的协程生命周期,要是大于所需要展示UI的界面的生命周期时,就会导致不必要资源浪费。
既然Activity、Fragment、协程、ViewModel、LiveData,甚至我们常用的Handler等所有对象,都需要严格管理生命周期,所以管理这些组件的生命周期就非常重要,这里大概能得到2点关于生命周期的需求:
-
给
Activtiy和Fragment这种常用的、显示UI的组件,搞一个统一的生命周期表示规则,这样就可以极大地方便开发者。比如我们都希望在页面对用户可见时,才更新UI,对用户不可见时,更新UI是无用功。但是比如
Fragment就比Activity多了onCreateView、onViewCreated等几个生命周期函数,Fragment的View对于可见这个判断就和Activity不一样了,这就导致开发者完成一个功能,需要对接多个组件。 -
可以获取和监控组件的统一生命周期函数变化。比如不论是
Activity还是Fragment,我们都希望在回调其onDestroy()方法前,释放一些资源,避免造成内存泄漏和资源浪费。
所以Lifecycle组件就被开发出来了,面对需要对接多个组件的复杂情况,一个有用的方法就是抽象出一层,而Lifecycle的思想也是如此,让本来开发者需要多个组件的情况下,现在就变成了对接一个组件。
如上图所示,有了Lifecycle后,就可以统一组件的生命周期了,这样我们在开发时就可以面向Lifecycle这一个组件了,这里我们以使用StateFlow为例,一般是调用LifecycleOwner(生命周期持有者)的repeatOnLifecycle方法:
//该方法为lifecycle-runtime-ktx中方法,用于监听Satate类型的uiState的变化
public suspend fun LifecycleOwner.repeatOnLifecycle(
state: Lifecycle.State,
block: suspend CoroutineScope.() -> Unit
): Unit = lifecycle.repeatOnLifecycle(state, block)
该方法配合StateFlow使用以达到和使用LiveData一样的效果,测试代码如下:
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 当LifecycleOwner的状态在STARTED及以上时,会触发block执行
// 当ON_STOP事件发生时,block协程会被取消
// 当LifecycleOwner接收到ON_START事件时,会重新执行block
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
uiStateFlow.collect { uiState ->
updateUi(uiState)
}
}
}
}
}
从这里代码注释我们可以看出,这里其实实现了类似LiveData的效果:会在Activity可见时绘制UI,在Activity销毁时取消协程,保证协程的生命周期可控,可以有效地节省资源和防止内存泄漏。
而这个的关键方法repeatOnLifecycle就是LifecycleOwner的扩展函数,这里不仅仅Activity是LifecycleOwner,Fragment也是实现该接口,这也就是前面所说的我们开发新功能时只需要面对Lifecycle这一个抽象层的组件即可。
正文
既然我们想把生命周期给抽象出来,再结合生命周期的作用,这里我们就可以思考一下,应该给抽象为几个部分。在Android中的Lifecycle框架库中,主要涉及的类如下:
classDiagram
class LifecycleOwner{
<<interface>>
---
+Lifecycle getLifecycle()
}
LifecycleOwner --> Lifecycle
class Lifecycle{
<<Abstract>>
AtomicReference<Object> mInternalScopeRef
+addObserver(@NonNull LifecycleObserver observer) void
+removeObserver(@NonNull LifecycleObserver observer)
+getCurrentState() State
}
Lifecycle ..> LifecycleObserver
class LifecycleObserver{
<<interface>>
---
}
Lifecycle ..> State
class State{
<<enum>>
DESTROYED
INITIALIZED
CREATED
STARTED
RESUMED
+isAtLeast(@NonNull State state) boolean
}
class FullLifecycleObserver{
<<interface>>
}
LifecycleObserver <|-- FullLifecycleObserver
class DefaultLifecycleObserver{
<<interface>>
}
FullLifecycleObserver <|-- DefaultLifecycleObserver
class LifecycleEventObserver{
<<interface>>
}
LifecycleObserver <|-- LifecycleEventObserver
class Activity{
+getLifecycle() Lifecycle
}
class Fragment{
+getLifecycle() Lifecycle
}
LifecycleOwner <|.. Activity
LifecycleOwner <|.. Fragment
这里如果对UML类图还不熟悉的,可以查看文章:# 效率提升 | UML类图。
从上面UML类图我们可以知道如下信息:
-
我们常用的
Activity和Fragment都是实现了LifecycleOwner接口,即为生命周期持有者,而LifecycleOwner是单方法接口,我们可以调用其getLifecycle()方法返回一个Lifecycle对象。 -
Lifecycle是一个抽象类,从其定义的3个方法来分析,主要就2个作用:- 通过添加和移除观察者的观察者模式,我们可以监听
Lifecycle派发的事件,观察者统一定义为LifecycleObserver接口。 - 通过
getCurrentState()方法,我们可以获取当前Lifecycle的状态,这里的状态State是一个枚举类型。
- 通过添加和移除观察者的观察者模式,我们可以监听
这也印证了文章刚开始我们抽象Lifecycle的本意,我们先不急着探究其原理,我们先来思考一下,我们如何使用这些提供的API。
Lifecycle的基本用法
第一种用法就是前面所说的,可以监听Lifecycle所派发的生命周期事件,测试代码如下:
//Activity中代码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
Logger.d("source = $source event = $event")
}
})
}
由于Activity实现了LifecycleOwner接口,所以这里可以获取Lifecycle对象,通过addObserver()方法可以添加观察者,这里的LifecycleEventObserver为LifecycleObserver的子接口:
classDiagram
class LifecycleObserver{
<<interface>>
---
}
class LifecycleEventObserver{
<<interface>>
+onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) void
}
LifecycleObserver <|-- LifecycleEventObserver
class Event{
<<enum>>
ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
ON_ANY
}
LifecycleEventObserver ..> Event
而这里的生命周期事件就是Event,对于Activity来说,其就是对应了其几个生命周期方法,所以上面测试代码中,我们把APP页面打开再关闭,打印如下:
第二种用法就是前面所说的可以调用getCurrentState()方法来获取当前Lifecycle的状态,对于状态State一共定义了5种枚举,至于为什么是5种,我们等会说原理时细说,这里我们大概和生命周期函数执行完的状态对应起来。
这里我们以LiveData来举例,LiveData是具有生命周期感知能力的观察者容器,所以有个特性:使用LiveData为数据源,做数据驱动来更新UI时,当UI页面不可见时,是不会更新UI的。
既然和生命周期有关,那就必须得用Lifecycle了,下面是利用LiveData更新UI:
//Activity中代码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.uiState.observe(this){
updateUI(it)
}
}
这里调用了LiveData的observe方法:
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer){
assertMainThread("observe");
//注释1
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
...
}
这里我们可以发现该方法第一个参数是LifecycleOwner,即生命周期持有者,而我们所熟悉的Activity就实现了该接口。在注释1处,会判断Lifecycle的当前状态,如果是DESTROYED的话,就没必要继续操作了,即当前生命周期组件已经是销毁状态了,完全没必要更新UI了。
这只是LiveData利用Lifecycle的getCurrentState()方法获取状态的一个使用之处,更多关于LiveData的生命周期感知能力,我们后面介绍LiveData时再说。
第三种使用Lifecycle组件的用法就是简化代码,核心思想是分离关注点,让原来需要在Activity/Fragment的生命周期方法中写的逻辑,给整理到一个生命周期观察者中,这里我们使用官方例子:
class MyActivity : AppCompatActivity() {
//地理位置监听器
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
//在onCreate方法中,创建监听器,根据监听器更新UI
myLocationListener = MyLocationListener(this) { location ->
// update UI
}
}
public override fun onStart() {
super.onStart()
//判断监听器是否被调用,开启服务
Util.checkUserStatus { result ->
// what if this callback is invoked AFTER activity is stopped?
if (result) {
myLocationListener.start()
}
}
}
public override fun onStop() {
super.onStop()
//及时暂停服务,防止资源浪费和内存泄漏
myLocationListener.stop()
}
}
上述代码我相信很多开发者都写过,为了服务能正常创建、启动以及关闭,我们必须保持服务的生命周期和Activity一致,这样可以防止内存泄漏和避免资源浪费,但是这就导致每个生命周期函数中逻辑过多,这时我们就可以利用Lifecycle来进行优化。
类似第一种使用方法,我们需要监听Lifecycle的生命周期改变事件,同时做一些处理,所以我们自定义一个观察者,代码如下:
//继承至DefaultLifecycleObserver
internal class MyLocationListener(
private val context: Context,
private val lifecycle: Lifecycle,
private val callback: (Location) -> Unit
): DefaultLifecycleObserver {
private var enabled = false
init{
lifecycle.addObserver(this)
}
//说明ON_START事件发生,可以看成Activity的onStart函数回调
override fun onStart(owner: LifecycleOwner) {
if (enabled) {
// connect
}
}
fun enable() {
enabled = true
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// connect if not connected
}
}
//说明ON_PAUSE事件发生,可以看成Activity的onStop函数回调
override fun onStop(owner: LifecycleOwner) {
// disconnect if connected
}
...
}
既然是添加观察者,所以必须是继承至LifecycleObserver接口,前面说了,这是一个空方法接口,第一种使用方法中,我们是使用了LifecycleEventObserver,这里我们使用DefaultLifecycleObserver接口,继承关系如下:
classDiagram
class LifecycleObserver{
<<interface>>
---
}
class FullLifecycleObserver{
<<interface>>
---
+onCreate(LifecycleOwner owner) void
+onStart(LifecycleOwner owner) void
+onResume(LifecycleOwner owner) void
+onPause(LifecycleOwner owner) void
+onStop(LifecycleOwner owner) void
+onDestroy(LifecycleOwner owner) void
}
class DefaultLifecycleObserver{
<<class>>
---
+onCreate(LifecycleOwner owner) void
+onStart(LifecycleOwner owner) void
+onResume(LifecycleOwner owner) void
+onPause(LifecycleOwner owner) void
+onStop(LifecycleOwner owner) void
+onDestroy(LifecycleOwner owner) void
}
LifecycleObserver <|-- FullLifecycleObserver
FullLifecycleObserver <|-- DefaultLifecycleObserver
这里的区别显而易见,就是把Event给细分为了这几个回调函数,同时提供了默认实现。
定义完自定义的观察者后,使用如下:
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
//只需要在onCreate中调用即可
myLocationListener = MyLocationListener(this, lifecycle) { location ->
// update UI
}
Util.checkUserStatus { result ->
if (result) {
myLocationListener.enable()
}
}
}
}
相比于最开始的代码,我们只需要在onCreate这一个生命周期函数中进行初始化即可,可以免去在多个生命周期函数中写逻辑,可以简化代码。
第四种用法主要是预防内存泄漏,在代码设计中,有个非常重要的原则是架构和业务分离,就比如我们常见的网络传输协议,TCP已经提供了可靠交付,就不需要我们在业务应用层里面再写关于可靠交付的逻辑了。
在整个Jetpack组件都是遵循这种原则的,比如我们文章最开始的例子,repeatOnLifecycle()方法中收集数据的协程,就会当Lifecycle处于DESTROYED时自动取消,这样就把合适时机取消协程,防止资源浪费和内存泄漏这个架构设计和业务逻辑给分开了,而不用我们在业务处理时,还考虑这些。
除此之外,还有非常多的小例子,比如这里防止内存泄漏的Handler:
//这里继承Handler,实现LifecycleEventObserver接口
class LifecycleHandler(val lifecycleOwner: LifecycleOwner) : Handler(),
LifecycleEventObserver {
init {
addObserver()
}
private fun addObserver() {
lifecycleOwner.lifecycle.addObserver(this)
}
//当生命周期持有者状态为DESTROYED时,移除所有消息和回调,保证可以正常被GC回收
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_DESTROY) {
removeCallbacksAndMessages(null)
lifecycleOwner.lifecycle.removeObserver(this)
}
}
}
由于Activity和Fragment都是实现了LifecycleOwner接口,所以所有依赖Activity和Fragment的类,都可以采取类似策略,比如Dialog等,将内存泄漏消灭在架构层逻辑。
看到这里,我相信你会有一些疑问。比如DefaultLifecycleObserver中的onCreate()回调是如何和Activity中的onCreate()回调保持联动的?有没有先后调用顺?换成Fragment为生命周期持有者,会不会有什么变化?
带着这些疑问,我们来分析一下其源码。
Lifecycle解析
既然Lifecycle是生命周期的抽象,主要用于获取当前生命周期状态以及派发生命周期事件,那么Activity和Fragment的生命周期函数个数是不一样的,所以这里需要定义一个更加通用的抽象层。
按照设计,表示Lifecycle的状态是State类,它一共有5种状态;而表示状态切换的事件,一共有7个,这里理解起来比较关键,官方有一个图如下:
这里我们以Activity为例,来解释一下这几种State含义:
-
根据枚举定义,每个枚举值都有一个
int类型ordinal值,表示定义枚举的顺序,这个值默认就是0到4,即State.DESTROYED最小,State.RESUMED最大,这也就是状态高低的说法,也是isAtLeast()方法执行的依据://State的方法 public boolean isAtLeast(@NonNull State state) { return compareTo(state) >= 0; }比如调用
isAtLeast(STARTED)为true,就说明当前Lifecycle状态为STARTED或者RESUMED。 -
我们所熟知的
Activity的生命周期函数如图:
这里不算onRestart()方法一共有6个,但是在前面我们定义的Lifecycle中State却没有这么多,所以这里要注意,这里的State更多的表示是一种状态,而非和生命周期函数一一对应。
- 这里对每一种
State做细致讲解:DESTROYED:它是最小状态,表示已经销毁的状态,在这个状态的Lifecycle将不再分发任何生命周期事件Event,这个状态在Activity的onDestroy()调用前到达。INITIALIZED:表示初始化状态,表示Activity已经被创建,但是还没有回调onCreate()方法,即在onCreate()方法回调前的状态是该状态。CREATED:表示已创建的状态,注意这种状态不仅仅在Activity的onCreate()方法回调后到达,而且在onStop回调前也是属于该状态,简单来说就是处于CREATED状态时,组件已经被创建,但是不可见且不可交互。STARTED:表示可见状态,但是无法交互,所以这种状态在onStart()回调后和onPause()回调前到达。RESUMED:表示处于可交互的running状态,这也只有在onResumd()回调后到达。
上面我们以Activity生命周期为例,分析了各种State的作用,可以总结为下图:
这里我们可以知道一个完整的Activity生命周期,其State状态是从小到大,再到小,这也是符合我们抽象生命周期的理念:我们更侧重想知道当前Lifecycle的状态,比如是否可见,是否已经被销毁,方便对应逻辑操作,而生命周期变化的事件,由Event来定义和派发。
说完了State,我们来看看其向观察者所派发的Event事件,这里搞清楚一个设计思路:Lifecycle的状态切换是由Event所导致,所以可以认为State就是一个图中的节点,而Event就是连接节点的边。
前面我们是以Activity来说明State的,其实真实的Event设计的差不多,也是对应着几种回调函数来设计的,Event是枚举类,共有6种事件,以及一系列状态切换方法,我们举个简单例子来说明Event工作流程:
sequenceDiagram
Activity ->> Observer:注册观察者
Activity -->> Activity:onCreate()回调
Activity ->> Observer:派发ON_CREATE事件
Observer -->> Observer:逻辑处理
所以Event的定义共如下几种:ON_CREATE、ON_START、ON_RESUME、ON_PAUSE、ON_STOP和ON_DESTROY,至于各自的含义,这里不多说了,就是和生命周期回调函数对应。
这里有个难点,就是Event中定义的几个方法,配合State使用,我们来分析一下。
downFrom方法定义如下:
public static Event downFrom(@NonNull State state) {
switch (state) {
case CREATED:
return ON_DESTROY;
case STARTED:
return ON_STOP;
case RESUMED:
return ON_PAUSE;
default:
return null;
}
}
解释:当从参数state离开往更低的状态切换,需要分发的Event。这里的downFrom函数名我们要分开看,其中down表示动词,表示向下,而from就是说明从哪个状态开始,这里结合前面的状态图一起,看代码实现:
- 我们从
CREATED状态开始,向下降低状态,根据状态图,它下一个状态就是DESTROY,需要派发ON_DESTROY事件来完成状态切换。
- 我们从
STARTED状态开始,向下降低状态,根据状态图,它的下一个状态是CREATED,需要派发ON_STOP事件来完成状态切换。
类似的方法还有downTo:
public static Event downTo(@NonNull State state) {
switch (state) {
case DESTROYED:
return ON_DESTROY;
case CREATED:
return ON_STOP;
case STARTED:
return ON_PAUSE;
default:
return null;
}
}
其中down是动词表示向下,to表示期望到达某个状态,这里我们需要注意一点:不论是down,还是后面要说的up,状态变化只能一步一步来。
即我想从RESUMED状态,下降到CREATED状态,根据状态图必须先下降到STARTED状态,再下降到CREATED状态,所以我们再看前面downTo的实现,当期望下降的状态是DESTROYED时,根据一次只能下降一步的原则,其实它的上一个状态就是CREATED,所以需要派发ON_DESTROY事件来完成状态切换。
这里还有类似的upFrom()和upTo()方法,我们就不分析了,但是我们要理解其设计思路:这些方法有什么用?
不管是down还是up,它的目的都是改变状态State的值,那我直接改变其值不就好了吗?为什么要知道每一步改变的事件呢?
这就涉及一个思想:永远是事件驱动状态变化,即事件导致状态变化。这里体现为2个方面:
- 对于
Activity这种生命周期持有者来说,永远都是其自己的onCreate()方法回调后,收到了ON_CREATE事件,其状态才变化为CREATED状态。 - 对于新添加的观察者来说,观察者默认状态是初始化状态,这时假如被观察者已经是
RESUMED状态,这时需要提升新添加的观察者的状态,从INITIALIZED提升到RESUMED,在这个过程中,需要一步一步派发Event,直到提升到RESUMED状态。
这2个方面第一个非常好理解,我们来看第二点,第二点其实就对应着Lifecycle的2个重要函数:addObserver和removeObserver。
这里暂时还没有到分析原理的地方,我们可以先说结论,等后面分析原理时再验证一下:
- 对于
addObserver方法,它是添加一个观察者,当被观察者的状态发生变化时,会通知观察者。
被添加的观察者状态,会被提高到和被观察者一样的状态。比如
LifecycleOwner的状态是STARTED,这个刚被添加的观察者,就需要派发ON_CREATE和ON_START事件。
- 对于
removeObserver方法,它是移除一个观察者。
到这里我们仅仅在接口层分析了Lifecycle的使用,那么接下来就是重点工作了,我们来分析一下Lifecycle是如何对Activity和Fragment进行抽象和封装的。
Lifecycle原理解析
从前面接口和使用分析,我们知道Lifecycle是观察者模式,可以用来获取当前Lifecycle的State,以及通过观察者来监听Lifecycle所派发的Event。
所以这里我们需要知道Lifecycle是如何进行抽象的,是如何添加/移除观察者,以及如何派发Event,即
这一部分的工作原理,我们先以Activity为例来解析源码。
话不多说,我们还是先来看看相关类的关系:
classDiagram
ViewModelStoreOwner <|.. ComponentActivity
LifecycleOwner <|.. ComponentActivity
ComponentActivity <|-- FragmentActivity
FragmentActivity <|-- AppCompatActivity
class ComponentActivity{
-LifecycleRegistry mLifecycleRegistry
+getLifecycle() Lifeycle
}
ComponentActivity --> LifecycleRegistry
Lifecycle <|-- LifecycleRegistry
class Lifecycle{
<<Abstract>>
AtomicReference<Object> mInternalScopeRef
+addObserver(@NonNull LifecycleObserver observer) void
+removeObserver(@NonNull LifecycleObserver observer)
+getCurrentState() State
}
class LifecycleRegistry{
-State mState
-FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap
-WeakReference<LifecycleOwner> mLifecycleOwner
+handleLifecycleEvent(@NonNull Lifecycle.Event event) void
+addObserver(@NonNull LifecycleObserver observer) void
+removeObserver(@NonNull LifecycleObserver observer) void
+getCurrentState() State
}
AppCompatActivity <|-- MainActivity
这里我们可以发现ComponentActivity实现了LifecycleOwner接口,即我们平时使用Activity就是生命周期持有者。
我们调用getLifecycle()方法时,其实就是返回ComponentActivity中定义的LifecycleRegistry类型的mLifecycleRegistry成员变量:
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
而且LifecycleRegistry实现了Lifecycle接口,所以这里使用了代理模式,所有操作都由这个LifecycleRegistry来实现。
我们先不去看其源码,我们先来分析一下Activity生命周期事件是什么时候派发给LifecycleRegistry的。
原本我以为分发生命周期事件,会在ComponentActivity的各个生命周期回调函数中调用LifecycleRegistry方法来派发事件,看了源码发现是利用了ReportFragment来实现的,调用关系如下:
sequenceDiagram
ComponentActivity ->> LifecycleRegistry: 持有变量
Note right of LifecycleRegistry:INITIALIZED
LifecycleRegistry ->> Observer:注册观察者
ComponentActivity ->> ComponentActivity:onCreate()
ComponentActivity ->> ReportFragment:injectIfNeededIn(this)
ComponentActivity -->> ReportFragment:更新依附的Fragment生命周期
ReportFragment ->> ReportFragment:onActivityCreated()
ReportFragment ->> ReportFragment:dispatch(Event.ON_CREATE)
ReportFragment ->> ReportFragment:dispatch(getActivity(), Event.ON_CREATE)
ReportFragment ->> LifecycleRegistry:handleLifecycleEvent(Event.ON_CREATE)
Note right of LifecycleRegistry:CREATED
LifecycleRegistry ->> Observer:notify()
上面黄色的Note表示Lifecycle的当前State,由这里我们可以验证最开始说的State含义:其中INITIALIZED初始化状态表示组件已经被创建,但是没有收到ON_CREATE事件,当收到ON_CREATE事件,状态切换到CREATED状态。
这里为什么可以使用ReportFragment的生命周期回调函数中来分发Activity的生命周期Event呢?这就涉及了Activity和Fragment生命周期函数的调用关系,如下图:
虽然这里Fragment比Activity多几个生命周期函数,但是丝毫不影响我们使用Fragment的生命周期来派发其所依赖的Activity的生命周期事件。
通过简单查看源码,对应关系如下:
Activity的ON_CREATE事件在Fragment中的onActivityCreated()方法中分发。ON_START、ON_RESUME、ON_PAUSE、ON_STOP和ON_DESTROY都是由其同名生命周期方法中分发。
这里分发事件的方法就是调用LifeycleRegistry的handleLifeEvent()方法,该方法我们后面细说。
说完了Activity是如何适配Lifecycle的,主要就是能够正确地、合理地派发Event给LifecycleRegistry,我们接着来看一下Fragment的流程,因为Fragment有一点不一样,它在派发Event有2套逻辑。
我们一般使用LiveData作为观察者容器,在Fragment的onViewCreated()方法中进行数据观察和更新UI:
这里我们使用this即Fragment对象作为LifecycleOwner居然会报错,提醒使用viewLifecycleOwner作为生命周期持有者,那这里这2个生命周期持有者有什么区别呢?如果强行使用this会有什么问题呢?
带着问题看源码,就有了探索思路,首先就是Fragment它是实现了LifecycleOwner接口的,相关类如下:
classDiagram
ViewModelStoreOwner <|.. Fragment
LifecycleOwner <|.. Fragment
Fragment <|-- BusinessFragment
class Fragment{
+LifecycleRegistry mLifecycleRegistry
+getLifecycle() Lifecycle
}
Lifecycle <|-- LifecycleRegistry
class Lifecycle{
<<Abstract>>
AtomicReference<Object> mInternalScopeRef
+addObserver(@NonNull LifecycleObserver observer) void
+removeObserver(@NonNull LifecycleObserver observer)
+getCurrentState() State
}
class LifecycleRegistry{
-State mState
-FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap
-WeakReference<LifecycleOwner> mLifecycleOwner
+handleLifecycleEvent(@NonNull Lifecycle.Event event) void
+addObserver(@NonNull LifecycleObserver observer) void
+removeObserver(@NonNull LifecycleObserver observer) void
+getCurrentState() State
}
Fragment --> LifecycleRegistry
和Activity一样,通过getLifecycle获取的依旧是LifecycleRegistry实例,工作机制一样,当Fragment的生命周期变化时,通过调用handleLifeEvent()来保存和处理事件,我们只需要知道在什么时候会派发事件即可,下面是源码总结:
| 调用链 | 派发的Event | Lifecycle状态 |
|---|---|---|
Fragment()构造函数 -> initLifecycle()创建LifecycleRegistry实例 | 无 | INITIALIZED |
performCreate() -> onCreate() -> mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) | Lifecycle.Event.ON_CREATE | CREATED |
performStart() -> onStart() -> mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START) | Lifecycle.Event.ON_START | STARTED |
performResume() -> onResume() -> mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) | Lifecycle.Event.ON_RESUME | RESUMED |
performPause() -> mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) -> onPause() | Lifecycle.Event.ON_PAUSE | STARTED |
performStop() -> mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) -> onStop() | Lifecycle.Event.ON_STOP | CREATED |
performDestroy() -> mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) -> onDestroy() | Lifecycle.Event.ON_DESTROY | DESTROYED |
上面的代码调用流程再配合文章刚开始说的图,是不是可以完美契合上了!尤其是派发事件和生命周期回调函数的先后问题。
从这里的生命周期回调来看,我们可以得出结论:getLifecycle()获取的Lifecycle,其代表Fragment的生命周期。
那getViewLifecycleOwner()获取的Lifecycle有什么区别呢?话不多说,直接看源码,涉及的相关类:
classDiagram
Fragment <|-- BusinessFragment
class BusinessFragment{
+getViewLifecycleOwner() LifecycleOwner
}
class Fragment{
+FragmentViewLifecycleOwner mViewLifecycleOwner
+getViewLifecycleOwner() LifecycleOwner
}
Fragment --> FragmentViewLifecycleOwner
class FragmentViewLifecycleOwner{
-LifecycleRegistry mLifecycleRegistry
+handleLifecycleEvent(@NonNull Lifecycle.Event event) void
}
FragmentViewLifecycleOwner --> LifecycleRegistry
class LifecycleRegistry{
+handleLifecycleEvent(@NonNull Lifecycle.Event event) void
}
Lifecycle <|-- LifecycleRegistry
class SavedStateRegistryOwner{
<<interface>>
+getSavedStateRegistry() SavedStateRegistry
}
LifecycleOwner <|-- SavedStateRegistryOwner
SavedStateRegistryOwner <|-- FragmentViewLifecycleOwner
ViewModelStoreOwner <|-- FragmentViewLifecycleOwner
可以发现这里使用了代理模式,但是代理的是LifecycleOwner对象,所以这里的核心代码就是FragmentViewLifecycleOwner的实现,在这里面我们依旧还是利用LifecycleRegstry来管理和处理Event,所以我们的关键还是看看在什么时候调用了Event,总结如下:
| 调用链 | 派发的Evnet | viewLifecycle状态 |
|---|---|---|
performCreateView() -> FragmentViewLifecycleOwner(this, getViewModelStore())调用构造函数 -> onCreateView() -> mViewLifecycleOwner.initialize() | 无 | INITIALIZED |
restoreViewState() -> onViewStateRestored(savedInstanceState) -> mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) | Lifecycle.Event.ON_CREATE | CREATED |
performStart() -> onStart() -> mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START) | Lifecycle.Event.ON_START | STARTED |
performResume() -> onResume() -> mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) | Lifecycle.Event.ON_RESUME | RESUMED |
performPause() -> mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) -> onPause() | Lifecycle.Event.ON_PAUSE | STARTED |
performStop() -> mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_STOP) -> onStop() | Lifecycle.Event.ON_STOP | CREATED |
performDestroyView() -> mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) -> onDestroyView() | Lifecycle.Event.ON_DESTROY) | DESTROYED |
从这里的调用链和前面Fragment自己的Lifecycle做比较,我们可以明显发现ON_START、ON_RESUME、ON_PAUSE和ON_STOP事件的派发时机和Fragment自己的Lifecycle是一样的。
而其他几个Event的派发就和Fragment的View的关系更加密切了,这里也就说明一件事:Fragment的生命周期和其View的生命周期是不一样的,getViewLifecycleOwner()返回的viewLifecycleOwner,表示的是Fragment中View的生命周期。
至于区别,我们可以看一张官方的图:
从这张图我们可以得出以下结论:
View的Lifecycle比Fragment的Lifecycle要短。- 当
Fragment的Lifecycle为CREATED时,View的Lifecycle可能还没有创建,即使创建了,也会在View创建完成后才处于CREATED状态。 - 当
Fragment还处于CREATED状态时,就会调用onDestroyView()函数,这时View的Lifecycle就处于DESTROYED状态了。
分析完上面结论,我们就可以解决这个问题了:
为什么这里要使用View的Lifecycle而不是选择Fragment的Lifecycle。
原因非常简单,也就是我们期望更新UI是根据Fragment的View的生命周期来做处理,而不是Fragment的生命周期,那如果用错了,会导致什么问题呢?
这里涉及LiveData一个特性:当LifecycleOwner的Lifecycle处于DESTROYED状态时,会自动remove该LiveData观察者。
所以这里的uiData会在owner处于DESTROYED时自动移除监听,可以防止内存泄漏,并且只更新可见的有效的UI信息。
这里出问题的场景就是Fragment切换时,可以把旧FragmentA加入到回退栈中,并且打开新FragmentB,这时FragmentA会执行onDestroyView()方法,但是不会执行onDestroy()方法,这时因为Fragment并没有被销毁;
这里如果使用Fragment的作为LifecycleOwner,FragmentA就不会移除uiData这个观察者,因为它没有到DESTROYED状态;这时再按返回键,FragmentB出栈,FragmentA又重新显示出来,这时会重新回调onViewCreated()方法,又会重新添加一遍uiData这个观察者,导致重复添加观察者。
但是使用viewLifecycleOwner就不会出现这种情况,根据前面生命周期图可知,当执行到onDestroyView()方法时,Lifecycle就处于DESTROYED状态了,这时可以正常移除观察者。
LifecycleRegistry原理解析
看了前面的使用以及解析,我相信你肯定迫不及待地想对LifecycleRegistry进行探究了,看看官方是如何实现一个Lifecycle的。
这里有关LifecycleRegistry内容比较多,我一直保持一个看源码就是一个持续学习的心态,所以这一节的内容,会比较发散,哪里不懂就探个究竟,不感兴趣的可以忽略,不影响Lifecycle的整体学习。
还是回顾一下LifecycleRegistry的继承关系以及主要功能函数:
classDiagram
Lifecycle <|-- LifecycleRegistry
class Lifecycle{
<<Abstract>>
AtomicReference<Object> mInternalScopeRef
+addObserver(@NonNull LifecycleObserver observer) void
+removeObserver(@NonNull LifecycleObserver observer)
+getCurrentState() State
}
class LifecycleRegistry{
-State mState
-FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap
-WeakReference<LifecycleOwner> mLifecycleOwner
+handleLifecycleEvent(@NonNull Lifecycle.Event event) void
+addObserver(@NonNull LifecycleObserver observer) void
+removeObserver(@NonNull LifecycleObserver observer) void
+getCurrentState() State
}
LifecycleRegistry作为Lifecycle接口的实现类,可以处理多个观察者,根据接口定义,它有3方面作用:
mState属性代表的当前Lifecycle的状态,可以使用getCurrentState()方法来获取状态。- 通过观察者模型,利用
addObserver()和removeObserver()方法来添加和移除观察者,以及处理其中的逻辑。最主要的业务逻辑就是对观察者派发生命周期事件。 - 通过
handleLifecycleEvent()方法来对接Activity、Fragment等UI组件,这个在前面我们说过了,这些组件都是通过该方法来设置Lifecycle的状态。
先来看一下构造函数:
代码段1
//对外的构造函数
public LifecycleRegistry(@NonNull LifecycleOwner provider) {
this(provider, true);
}
//私有构造函数
private LifecycleRegistry(@NonNull LifecycleOwner provider, boolean enforceMainThread) {
mLifecycleOwner = new WeakReference<>(provider);
mState = INITIALIZED;
mEnforceMainThread = enforceMainThread;
}
//生命周期持有者,弱引用封装
private final WeakReference<LifecycleOwner> mLifecycleOwner;
private State mState;
//是否强制主线程
private final boolean mEnforceMainThread;
这里有个值得学习的点,就是这里把传递进来的LifecycleOwner用弱引封装起来,即这里的mLifecycleOwner对象,当使用时需要调用mLifecycleOwner.get()可以获取LifecycleOwner对象。
这里为什么要使用弱引用呢?由前面可知,这里的生命周期持有者一般都是Activity、Fragment这种重量级的组件类,假如我们通过getLifecycle()获取的Lifecycle发生了内存泄漏,使用弱引用将不会泄漏整个Activity和Fragment。
这里扩展一下:什么是内存泄漏,就是这个类该被GC回收了,发现还被引用则无法被回收,导致内存泄漏。就比如获取的lifecycle对象,被错误地传递给了一个全局变量,这时Activity页面关闭,需要被回收,会发现这里Activity是弱引用,依旧可以被GC回收。
弱引用作用:当一个类只被弱引用引用时,它也是可以被GC回收的。这个点还是比较值得我们平时学习的,防患于未然,假如引用到这种重量级的组件类,可以适当考虑使用弱引用,以防止内存泄漏。
然后就是处理Event的handleLifecycleEvent()方法:
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
enforceMainThreadIfNeeded("handleLifecycleEvent");
moveToState(event.getTargetState());
}
这里有个值得学习的点,就是如何判断当前线程是主线程,因为不仅仅这个方法,还包括添加/删除观察者都要求在主线程,我们来看一下:
private void enforceMainThreadIfNeeded(String methodName) {
if (mEnforceMainThread) {
if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Method " + methodName + " must be called on the "
+ "main thread");
}
}
}
@Override
public boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
可以发现这里是利用Looper来实现的,获取主线程Looper中的线程信息,是否等于当前线程,关于主线程Looper是何时创建和保存线程信息的,等后面有机会介绍Looper时再说。
我们继续业务分析,这一行代码moveToState(event.getTargetState())中的getTargetState()方法就是获取当前event期望的状态,这里配合源码和前面所说的State与Event关系图非常好理解:
//Event的方法,获取当前event后的状态
public State getTargetState() {
switch (this) {
case ON_CREATE:
case ON_STOP:
return State.CREATED;
case ON_START:
case ON_PAUSE:
return State.STARTED;
case ON_RESUME:
return State.RESUMED;
case ON_DESTROY:
return State.DESTROYED;
case ON_ANY:
break;
}
throw new IllegalArgumentException(this + " has no target state");
}
比如Activity派发了ON_CREATE事件给Lifecycle,根据逻辑,当前Lifecycle的期望状态就是CREATED,然后就是moveToState()方法:
代码段2
//切换Lifecycle到next状态
private void moveToState(State next) {
if (mState == next) {
return;
}
//根据上图可知,状态是无法一次从`INITIALIZED`下降到`DESTROYED`
if (mState == INITIALIZED && next == DESTROYED) {
throw new IllegalStateException("no event down from " + mState);
}
mState = next;
//当正在处理Event或者正在添加观察者时,直接return
if (mHandlingEvent || mAddingObserverCounter != 0) {
mNewEventOccurred = true;
return;
}
//处理Event的过程
mHandlingEvent = true;
sync();
mHandlingEvent = false;
//当状态处于DESTROYED时,清空观察者集和
if (mState == DESTROYED) {
mObserverMap = new FastSafeIterableMap<>();
}
}
//是否正在处理事件,即执行`sync()`方法期间
private boolean mHandlingEvent = false;
//是否有新的事件产生
private boolean mNewEventOccurred = false;
//正在添加的观察者有几个
private int mAddingObserverCounter = 0;
这里代码的flag比较多,其实在日常开发中,为了可读性,代码还是需要尽量少的使用flag。这里为什么要使用这么多flag呢?
其实根源就是处理Event的方法和添加/移除观察者都是在主线程上执行的,需要加快执行效率。首先就是一个Lifecycle可以添加多个观察者,由代码可知这些观察者在封装后保存在mObserverMap这个集和中,然后每当Lifecycle的状态发生变化时,需要通知这些观察者,这些观察者再去派发事件。
而这个过程,就是上面的sync()方法,即表示处理Event过程,这里的mHandingEvent就是表示是否在这个过程,我们来看一下该方法:
代码段3
//同步过程,即处理Event的过程
private void sync() {
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
//生命周期持有者可能被回收了
if (lifecycleOwner == null) {
throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
+ "garbage collected. It is too late to change lifecycle state.");
}
//当没有同步完成时
while (!isSynced()) {
//进行一次同步
//由于mState是全局变量,假如有新的Event要处理,这时说明已经在处理了,
//所以mNewEventOccourred置为false
mNewEventOccurred = false;
//当前状态小于链表最大值,需要降低状态
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
backwardPass(lifecycleOwner);
}
//当前状态大于链表最小值,进行前进提升处理
Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
forwardPass(lifecycleOwner);
}
}
mNewEventOccurred = false;
}
//是否是期望的同步完状态
private boolean isSynced() {
if (mObserverMap.size() == 0) {
return true;
}
//最老观察者的状态
State eldestObserverState = mObserverMap.eldest().getValue().mState;
//最新观察者状态
State newestObserverState = mObserverMap.newest().getValue().mState;
//最老最新状态一样且Lifecycle当前状态等于最新状态
return eldestObserverState == newestObserverState && mState == newestObserverState;
}
//保存观察者的集和
private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
new FastSafeIterableMap<>();
上面信息比较多,主要作用就是同步所有观察者的状态,这个什么意思呢?
假如当前Lifecycle有4个观察者,以链表形式保存,每个观察者状态分别为1 -> 1 -> 1 -> 1,根据枚举值,这里的1就是INITIALIZED状态,这时Lifecycle收到了ON_CREATE事件,根据切换图,这时Lifecycle为CREATED状态,这时就需要同步4个观察者的状态,通知观察者的回调函数,需要派发ON_CREATE事件,即把状态变为2 -> 2 -> 2 ->2这样,就算是同步完成。
这里需要再补充一下保存观察者的集和mObserverMap,这个集和比较特殊,后面详细学习介绍一下,这里大概说一下,FastSafeIterableMap就是一个简易版的LinkedHashMap,可以在遍历时增加和删除,保存着观察者,但是它有一个不变的特性:在任何时候,对于Observer1和Observer2来说,如果被Observer1的添加顺序小于Observer2的添加顺序,那么Observer1的状态要大于等Observer2。
这个特性说人话就是这个mObserverMap虽然是个Map,但是添加的Observer是有顺序的,任何时候,早添加的值都不小于晚添加的,即这是一个非递增链表。
假如有3个观察者,其状态可能是3 -> 2 -> 2,或者3 -> 2 -> 1,绝对不会是2 -> 3 -> 2这种状态。
简单了解完mObserverMap的保存特性后,再来分析上面同步过程,假如现在有3个观察者,状态分别为2 -> 2 -> 1,这时Lifecycle收到ON_START事件,mState切换为STARTED,这时需要同步3个观察者状态,根据前面代码段3中判断:当前Lifecycle的mState为3,3比链表最大值2要大,不会执行backwardPass()方法;同时3又比链表最小值1要大,所以需要执行forwardPass()方法:
代码段4
private void forwardPass(LifecycleOwner lifecycleOwner) {
//获取一个升序遍历迭代器
Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
mObserverMap.iteratorWithAdditions();
//当没有遍历完,且没有新的Event发生
while (ascendingIterator.hasNext() && !mNewEventOccurred) {
//当前节点
Map.Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
//当前节点的值
ObserverWithState observer = entry.getValue();
//当前节点状态低于mState的状态
//没有新的Event需要派发
//当前节点还没有被删除
while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
&& mObserverMap.contains(entry.getKey()))) {
//暂时忽略
pushParentState(observer.mState);
//提升一级状态,需要派发的Event
final Event event = Event.upFrom(observer.mState);
if (event == null) {
throw new IllegalStateException("no event up from " + observer.mState);
}
//通知观察者派发Event
observer.dispatchEvent(lifecycleOwner, event);
popParentState();
}
}
}
在了解完mObserverMap的非递增特性后,再来看看这段逻辑就非常好理解了,即forward(提升)所有观察者的状态,这里使用的是升序遍历迭代器,即从大到小进行提升状态,即使被中断了,执行到一半的队列也是符合非递增特性的。每一个观察者自己也需要一个状态,这个待会在添加观察者时细说。
在代码实现中,我们可以看见有2层while循环,也就说明这是一个比较耗时的操作,而这也就体现了mNewEventOccurred和mHandingEvent的作用了。
我们来举个例子,假如现有的观察者状态为2,2,1,这时handleLifecycleEvent收到了ON_START事件,这时mState变为3,期望观察者队列同步为3,3,3,此时就需要执行这个耗时的forwardPass()方法,在这期间,mHandingEvent为true。假如这时刚同步到3,2,1状态,又收到了ON_RESUME事件,这时代码段2又被执行了,mState变为4,但是由于前一个同步还没有完成,这时mNewEventOccurred就变成了true,这时forwardPass()会停止执行,回到代码段3中的while循环,重新设置期望的队列为4,4,4,然后再执行forwardPass()方法,根据2层while遍历,把3,2,1提升到4,4,4。
由于都是主线程,所以这里也没有线程安全问题,通过2个变量控制,让本来需要执行多次的方法,可以就执行一次完成逻辑实现,大大地减缓主线程的压力。
与forwardPass()对应的方法是backwordPass()方法,从这里我们就可以反推出为什么Event中需要设计比如downFrom()、downTo()等方法了。
从代码段4中的2个while循环,我们也可以验证一个结论,就是状态提升和下降都是一步一步执行,是通过事件驱动,即一个观察者状态从CREATED提升到RESUMED,就必须要派发ON_START和ON_RESUME这2个事件。
我们继续来看业务逻辑流程,说完了处理Lifecycle的Event,来看看如何添加观察者Observer,以及派发Event。
代码段5
public void addObserver(@NonNull LifecycleObserver observer) {
//强制在主线程
enforceMainThreadIfNeeded("addObserver");
//被添加的观察者初始状态
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
//带状态的观察者,把observer进行封装
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
//是否已经被添加过,注意这里插入Map中的key是observer,value是statefulObserver
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
if (previous != null) {
return;
}
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
return;
}
//是否重新进入该方法操作,是否重复,即正在添加观察者或者正在处理Event
boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
//计算新添加的observer的期望目标State
State targetState = calculateTargetState(observer);
//正在添加的Observer个数加1
mAddingObserverCounter++;
//由于初始状态是INITIALIZED,所以只需要提升到目标状态即可
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
//暂时不管
pushParentState(statefulObserver.mState);
//提升状态
final Event event = Event.upFrom(statefulObserver.mState);
if (event == null) {
throw new IllegalStateException("no event up from " + statefulObserver.mState);
}
//观察者需要派发事件
statefulObserver.dispatchEvent(lifecycleOwner, event);
popParentState();
//再次计算期望目标State
targetState = calculateTargetState(observer);
}
//在非重复状态下,进行同步
if (!isReentrance) {
// we do sync only on the top level.
sync();
}
//进行减1
mAddingObserverCounter--;
}
//计算一个observer的期望目标State
private State calculateTargetState(LifecycleObserver observer) {
//获取该observer链表的前一个节点
Map.Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
//前一个节点的状态
State siblingState = previous != null ? previous.getValue().mState : null;
//获取parentState状态
State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
: null;
//返回最小者
return min(min(mState, siblingState), parentState);
}
addObserver流程比较复杂,细节较多,我们先分析主体业务流程:
-
首先就是对添加的
observer进行封装为ObserverWithState,即把状态和observer封装到一起,正常情况下,状态是初始状态。 -
然后添加到
mObserverMap中,这里的插入时key是observer,value是ObserverWithState。 -
isReentrance表示是否重入,这代表什么意思呢?这里又涉及主线程的处理Event和添加观察者操作是否重复,比如刚调用addObserver()方法,还没有执行完,又调用,这时mAddingObserverCounter就不为0,表示添加观察者的操作重复了。再比如调用
addObserver()时,Lifecycle正在处理事件,这也是说明2个操作之间重复了。这可以看出在这2种情况下,是不会调用sync()方法的。 -
sync()方法是同步所有观察者状态和mState一致以及分发Event,结合这里的isReentrance和代码段2中的判断条件,我们可以得出如下结论:- 先执行
Event处理,没处理完,这时再执行Event处理,操作重复,会直接return掉,前面说了,可以提高执行效率。 - 先执行
Event处理,没处理完,再执行添加观察者,操作重复,判断为重复操作,在提升完新添加的观察者状态后,addObserver()不会进行sync()同步,因为处理Event方法正在同步。 - 先执行添加观察者,在提升状态时,再执行
Event处理,在添加观察者方法中,是不重复操作的,这时可以执行sync(),但是在moveToState()中,mAddingObserverCounter不为空,不会进行重复执行。
说了这么多,还是那句话,就是为了让
sync()这个方法少执行,以提高主线程执行效率,同时避免同步状态派发事件和添加观察者操作重叠导致问题。 - 先执行
-
对于新添加的
observer需要计算其期望的目标状态,由于链表是非递减的,所以在插入到链表尾后,其目标状态就是前一个节点的状态。比如原来链表是
3,3,添加进来的原始为1,即为3,3,1,这时通过calculateTargetState()中的ceil()方法就可以得到其期望值为3。这里这种逻辑非常合理,但是为什么
calculateTargetState()方法还涉及了mParentState变量呢?这是一个及其细微的细节,这里要考虑下面这种极端情况:
//这是一个观察者,当派发`ON_START`事件时,会触发该回调方法 void onStart(){ mRegistry.removeObserver(this) mRegistry.add(newObserver) }首先这段代码是在一个
Observer中写的,且当前Lifecycle中只有this这一个观察者,根据前面我们所梳理的Lifecycle处理Event流程,当this这个观察者执行onStart()方法时(还没有执行removeObserver),说明正在派发ON_START事件,这时Lifecycle的mState为STARTED状态,观察者队列应该是CREATED -> NULL状态,这是因为在分发Event中,会先回调方法,再改变链表中Observer的状态,代码执行的地方应该是代码段4中的forwardPass()函数部分,即同步状态和派发事件。当执行完
mRegistry.removeObserver(this)时,根据源码:
@Override
public void removeObserver(@NonNull LifecycleObserver observer) {
enforceMainThreadIfNeeded("removeObserver");
mObserverMap.remove(observer);
}
可以发现这里直接会把this从链表中删除,即这时mObserverMap为空的。
然后执行mRegistry.add(newObserver),根据前面源码可知需要提升newObserver的状态,j计算提升状态方法为calculateTargetState():
//计算一个observer的期望目标State
private State calculateTargetState(LifecycleObserver observer) {
//获取该observer链表的前一个节点 1
Map.Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
//前一个节点的状态 2
State siblingState = previous != null ? previous.getValue().mState : null;
//获取parentState状态 3
State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
: null;
//返回最小者 4
return min(min(mState, siblingState), parentState);
}
static State min(@NonNull State state1, @Nullable State state2) {
return state2 != null && state2.compareTo(state1) < 0 ? state2 : state1;
}
在这种情况下,代码1和2行获取的就会是null,假如没有代码3这一行,通过min函数计算就会返回mState,从前面可知mState为STARTED状态。
这时就有问题了:this的onStart()方法还没有执行完,在它后面的观察者状态只能小于它,即newObserver被添加进来后,状态应该被提升到CREATED,而不是STARTED。
那这时代码行3就有了作用,通过查看代码,我们可以发现,在执行事件分发的forwardPass()方法中,会记录分发前的状态,然后分发完再移除,通过这个逻辑,代码行3就能够获取已经被删除的this状态:CREATED,这也就符合逻辑了。
分析完添加观察者后,主要逻辑的处理Event和添加/删除观察者就说完了,我们来聊一些不是非常重要的知识点。
首先就是前面刻意忽略的添加observer时,对观察者的封装了,调用代码如下:
public void addObserver(@NonNull LifecycleObserver observer) {
enforceMainThreadIfNeeded("addObserver");
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
...
}
这里的类是ObserverWithState,它封装了观察者,主要作用是持有状态和派发事件(回调事件),类定义如下:
static class ObserverWithState {
//观察者所持有的状态
State mState;
//观察者事件回调函数
LifecycleEventObserver mLifecycleObserver;
//构造方法
ObserverWithState(LifecycleObserver observer, State initialState) {
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
//派发事件
void dispatchEvent(LifecycleOwner owner, Event event) {
//该Event的目标State
State newState = event.getTargetState();
//取最小值
mState = min(mState, newState);
//业务代码执行
mLifecycleObserver.onStateChanged(owner, event);
//业务代码执行后,切换到新状态
mState = newState;
}
}
这个dispatchEvent()方法中内容的执行顺序,在前面解释mParentStates字段作用时说过了,会先进行回调,再设置新的状态。
这里构造函数中,使用Lifecycling中的静态方法,把空方法接口LifecycleObserver经过转换,变成了有方法的统一的LifecycleEventObser类型,这样我们在dispatchEvent方法中直接使用onStateChanged进行回调即可。
实际上,实现了LifecycleObserver这个空方法接口的类,有3种途径可以收到派发的Event,分别是前面所说过的LifecycleEventObser子类和FullLifecycleObser子类,还有一种方式是通过注解实现的,比如下面观察者:
class CustomObserver : LifecycleObserver{
//会收到`ON_RESUME`事件时调用该方法
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectGps(){
...
}
}
在实际写的时候,会发现这种方法已经被废弃了,官方不推荐这种写法,原因也非常简单,这种通过注解生成类的方式,效率比较低,建议使用DefaultLifecycleObserver接口。
还有一个知识点就是用来保存观察者的集和FastSafeIterableMap,它到底和我们常见的集和有什么特殊之处,我们来简单分析分析。
通过源码注释,我们知道它其实是一个简易版的LinkedHashMap,在迭代时可以修改增删元素,线程不安全,相比于SafeIterableMap会耗费更多内存,是典型的空间换时间的策略,类图如下:
classDiagram
SafeIterableMap <|-- FastSafeIterableMap
class FastSafeIterableMap{
-HashMap<K, Entry<K, V>> mHashMap
~get(K k) Entry
~putIfAbsent(@NonNull K key, @NonNull V v)
~remove(@NonNull K key)
~contains(K key)
~ceil(K k) Entry
}
这里提供了增删改查的常规API,其实这些功能其父类SafeIterableMap也都实现了,但是该类多了一个mHashMap变量,也就是会消耗更多的内存,而且其API都是基于该mHashMap的:
protected Entry<K, V> get(K k) {
return mHashMap.get(k);
}
public V putIfAbsent(@NonNull K key, @NonNull V v) {
Entry<K, V> current = get(key);
if (current != null) {
return current.mValue;
}
mHashMap.put(key, put(key, v));
return null;
}
你或许会疑问这样做的意义是什么呢?就是单纯的为了get()操作更快,这是因为其父类SafeIterableMap看着是一个Map结构,但是真正实现是用链表实现的,而链表这种数据结构,查询是非常慢的。
所以我们就来看看这个用链表伪装成Map的SafeIterableMap是如何实现的。
既然是链表,所以会有头尾节点:
//头节点
Entry<K, V> mStart;
//尾节点
private Entry<K, V> mEnd;
//前后节点
static class Entry<K, V> implements Map.Entry<K, V> {
@NonNull
final K mKey;
@NonNull
final V mValue;
Entry<K, V> mNext;
Entry<K, V> mPrevious;
...
}
这里就是熟悉的双向链表节点结构,我们再来看看增删改查几个API:
//链表尾部增加一个节点
protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
Entry<K, V> newEntry = new Entry<>(key, v);
//集和元素个数加一
mSize++;
//第一个节点
if (mEnd == null) {
mStart = newEntry;
mEnd = mStart;
return newEntry;
}
//尾插
mEnd.mNext = newEntry;
newEntry.mPrevious = mEnd;
mEnd = newEntry;
return newEntry;
}
//根据K,找到节点
protected Entry<K, V> get(K k) {
Entry<K, V> currentNode = mStart;
//从头开始遍历
while (currentNode != null) {
if (currentNode.mKey.equals(k)) {
break;
}
currentNode = currentNode.mNext;
}
return currentNode;
}
//删除节点
public V remove(@NonNull K key) {
//找到待删除的节点
Entry<K, V> toRemove = get(key);
if (toRemove == null) {
return null;
}
//个数减一
mSize--;
//通知迭代器,元素被删除了
if (!mIterators.isEmpty()) {
for (SupportRemove<K, V> iter : mIterators.keySet()) {
iter.supportRemove(toRemove);
}
}
//删除的是否是头节点
if (toRemove.mPrevious != null) {
toRemove.mPrevious.mNext = toRemove.mNext;
} else {
mStart = toRemove.mNext;
}
//删除的是否是尾节点
if (toRemove.mNext != null) {
toRemove.mNext.mPrevious = toRemove.mPrevious;
} else {
mEnd = toRemove.mPrevious;
}
toRemove.mNext = null;
toRemove.mPrevious = null;
return toRemove.mValue;
}
看到这里,你肯定会说就这?为什么Google程序员要费力气用链表实现一个Map,还不如使用HashMap呢?
首先它是支持在非迭代器遍历时进行删除的,不会报ConcurrentModificationException异常,这个特性非常重要,我们回顾一下,LifecycleRegistry在处理Event和addObserver()后都有一个非常关键的步骤,就是同步,并且说了关键的sync()函数是不会在这2个动作交叉、重复的情况下执行,但是移除观察者的removeObserver()方法却没有任何限制。也就是说完全可以在任何时候进行删除观察者,甚至在遍历的时候,这里不出错,就是该链表的作用。
还有一个特点就是提供了正序和反序的迭代器,对于HashMap来说我们是无法控制其遍历顺序是否和添加顺序一样的,再结合业务分析,前面我们说了observerMap中保存的观察者,是非递增的,即值和添加顺序有关,而且改变链表中的值也不能打破这个规则,所以正序和反序遍历就非常有必要。
话不多说,来看源码:
//Iterable接口实现方法,可用于快速遍历
//在迭代期间,不会包含新添加的元素
public Iterator<Map.Entry<K, V>> iterator() {
//返回一个正序迭代器
ListIterator<K, V> iterator = new AscendingIterator<>(mStart, mEnd);
//添加到迭代器队列中
mIterators.put(iterator, false);
return iterator;
}
//返回一个反序迭代器,同样在迭代期间,是无法保护新添加的元素
public Iterator<Map.Entry<K, V>> descendingIterator() {
DescendingIterator<K, V> iterator = new DescendingIterator<>(mEnd, mStart);
mIterators.put(iterator, false);
return iterator;
}
//返回一个正序迭代器,可以在迭代期间添加新元素,且可以迭代到
public IteratorWithAdditions iteratorWithAdditions() {
IteratorWithAdditions iterator = new IteratorWithAdditions();
mIterators.put(iterator, false);
return iterator;
}
//保存迭代器的集和
private WeakHashMap<SupportRemove<K, V>, Boolean> mIterators = new WeakHashMap<>();
这里提供了3种迭代器,这3种迭代器都支持在迭代时删除元素,其中iterator()和descendingIterator()返回的迭代器是ListIterator的子类,通过传入头尾节点来进行迭代,所以在迭代中对新添加的元素是无法感知的。
对于iteratorWithAdditions()返回的迭代器,是正序迭代,且可以感知遍历到在遍历中添加的元素。至于这3个迭代器的实现,我们就不看细节了,无外乎就是链表操作。
这里看一个值得学习的点,就是这个mIterators的数据类型:WeakHashMap。
在文章前面介绍Lifecycle原理是时也说到了弱引用,那是用来防止内存泄漏的。而这里的WeakHashMap则是用来节省内存,简化操作的。WeakHashMap对存放的键值对的Key(键)做了弱引用处理,当某个键值对没有强引用时,可以自动被移除,然后被GC回收。
假如这里存在多次调用迭代器的情况,虽然每次都把迭代器放进了mIterators,但是它的内存占用不会持续增加,会在适当时候释放这些迭代器对象的内存。至于为什么要保存这些迭代器,可以看一下上面remove()操作,在remove()时需要通知迭代器,这也是这些迭代器支持删除的原因。
ProcessLifecycleOwner解析
前面所说的都是以Activity和Fragment作为生命周期持有者的情况,其实还有一种常见的情况,就是以app应用作为生命周期持有者,也就是这里的ProcessLifecycleOwner即进程生命周期持有者。
使用如下:
//在App的OnCreate()方法中写如下代码
//Observer接口好几种写法,按需求选择
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver{
//只会派发一次
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
Logger.t("BaseApp").d("onCreate")
}
//当APP可见时派发
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
Logger.t("BaseApp").d("onStart")
}
//当APP可以交互时派发,这时APP处于前台
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
Logger.t("BaseApp").d("onResume")
}
//当APP不可交互时派发,即退出到后台
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
Logger.t("BaseApp").d("onPause")
}
override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
Logger.t("BaseApp").d("onStop")
}
//永远不会被派发
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
Logger.t("BaseApp").d("onDestroy")
}
})
上面的使用中,主要适用于一个场景:有些APP需要在退到后台时,需要提醒弹出Toast,比如一些银行APP。而且需要注意上面各种事件的派发次数。
老规矩,我们还是来看看这个整个应用的生命周期持有者是如何派发这些事件的。
首先一个APP正常来说就一个Application应用,所以这里ProcessLifecycleOwner应该保持单例:
public static LifecycleOwner get() {
return sInstance;
}
private static final ProcessLifecycleOwner sInstance = new ProcessLifecycleOwner();
private ProcessLifecycleOwner() { }
这里使用静态方法由JVM实现的单例,但是我们居然发现其构造函数居然是空的,那什么地方开始逻辑业务的呢?
这里就用到了一个小知识点,利用ContentProvider来启动初始化逻辑,这种用法在很多开源库都有使用,这里我们在XML中找到如下代码:
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge" >
<meta-data
android:name="androidx.lifecycle.ProcessLifecycleInitializer"
android:value="androidx.startup" />
</provider>
</application>
这里的InitializationProvider继承至ContentProvider,可以用来初始化一些app的信息,并且会在Application.onCreate()之前进行调用。
这里涉及startup库的使用,我们只需要知道,这里的初始化器是定义在meta-data中的ProcessLifecycleInitializer:
public final class ProcessLifecycleInitializer implements Initializer<LifecycleOwner> {
//初始化的实例
@NonNull
@Override
public LifecycleOwner create(@NonNull Context context) {
//给每一个Activity都hook一个ReportFragment
LifecycleDispatcher.init(context);
//初始化业务
ProcessLifecycleOwner.init(context);
return ProcessLifecycleOwner.get();
}
//所依赖的类
@NonNull
@Override
public List<Class<? extends Initializer<?>>> dependencies() {
return Collections.emptyList();
}
}
这样逻辑才对,利用ContentProvider我们可以确保在Application.onCreate()之前就开始初始化逻辑,我们来看看init()方法的逻辑:
static void init(Context context) {
sInstance.attach(context);
}
void attach(Context context) {
//主线程Handler
mHandler = new Handler();
//依旧是Registry来做事件分发
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
Application app = (Application) context.getApplicationContext();
//注册Activity的事件回调
app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
@RequiresApi(29)
@Override
public void onActivityPreCreated(@NonNull Activity activity,
@Nullable Bundle savedInstanceState) {
activity.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
@Override
public void onActivityPostStarted(@NonNull Activity activity) {
//有activity触发到onStarted()
activityStarted();
}
@Override
public void onActivityPostResumed(@NonNull Activity activity) {
//有activity触发onResumed()
activityResumed();
}
});
}
...
@Override
public void onActivityPaused(Activity activity) {
//触发onPause
activityPaused();
}
@Override
public void onActivityStopped(Activity activity) {
//触发onStop
activityStopped();
}
});
}
思路非常简单,每当一个Activity回调其生命周期函数时,进行记录,这种逻辑在之前我们经常在BaseActivity中写,来实现类似功能。
具体几个方法都比较简单,这里我们就不做源码的复制粘贴了,就是通过2个变量mStartedCounter和mResumedCounter来记录有多少Activity启动和销毁,当为0时就说明APP退到后台。
但是这里实现了一个特殊场景判断,即当应用发生配置变化,比如旋转,这时生命周期会重新回调,如果仅仅判断数量的话,会导致旋转时也会认为是进入到后台。
为了解决这个问题,源码中加了延迟处理以及mPauseSent等字段来加以判断,去除这种情况。
总结
不知不觉已经写了一万多字了,不得不说,这种优秀的库的源码就是一座宝藏,看源码的过程真的是一个持续学习的过程,不仅仅可以加深理解,更可以学习设计思路、实现思路和方法等。
还是做个总结吧,如下:
- 当人们面对复杂的的问题,一个有用的方法是分层和抽象,所以Lifecycle就是为了统一生命周期,提供一些公共的属性和方法,方便开发者对接。
-
在基本使用前,我们使用
UML类图来给出了关键类的关系,合理使用UML类图有利于快速构建关系。 -
在基本用法中,我们简单介绍了几种使用,包括:
- 监听Lifecycle所派发的生命周期事件;
- 获取当前Lifecycle状态;
- 根据分离关注点思想来简化代码,把逻辑从散落在生命周期函数中的逻辑给集中一起;
- 还有就是架构和业务分离,合理使用可以预防内存泄漏,比如配合协程、Handler、Dialog等。
-
在Lifecycle解析部分中,我们首先介绍了其中的State和Event,这里需要深刻理解该图:
结合图中示意,理解每个State的含义,以及关键的的downFrom、upFrom等方法设计思路和含义。
- 这里我们一直秉承一个思想就是事件驱动状态变化,
LifecycleOwner实现类比如Activity,派发Event驱动Lifecycle的状态变化,Lifecycle再派发事件,改变其观察者状态,同时状态变化不能跨级,只能一步一步变化。 - 在
Lifecycle原理解析部分,先是分析了最常见的组件Activity是在时候派发Event的,这部分我们涉及了ReportFragment的使用和介绍,这种巧妙利用Activity和Fragment关系的方式,可以看成是一种hook,来获取Activity生命周期回调。 - 实现
LifecycleOwner的核心是能够正确、合理派发Event给LifecycleRegistry。 - 在分析
Fragment派发Event中可知,有2个LifecycleOwner,一个是Fragment自己的,一个是其View的,通过分析调用链关系,我们可得如下图:
-
通过该图我们需要更加理解
Event和State的关系,以及和对应生命周期函数调用的先后关系。同时分析了在Fragment中使用viewlifecycle来替代lifecycle的原因,就是在旧Fragment入栈出栈,会导致重复添加观察者。 -
在
LifecycleRegistry原理部分就比较随意了,是保持学习心态来探究的,它是官方提供的Lifecycle接口的实现类,可以处理多个观察者。- 在构造函数有个值得学习借鉴的点,就是把
Activity或者Fragment使用弱引用封装,这种可以有效防止这种重量级的组件发生内存泄漏。 - 在派发事件中,由于要处理多个观察者状态同步和派发,所以这里使用
mHandingEvent和mNewEventOccurred这2个flag能避免多次执行,加快效率。 - 在派发事件和添加观察者这2个都是在主线程调用的函数,为了避免出错和效率,这里通过多个flag来确保
sync()方法只会运行在非嵌套动作的情况下。 - 其次我们学习了
SafeIterableMap这个数据接口,同时在LifecycleRegistry中它一直保持非递增的规则,实际上它是由链表实现的Map,支持在遍历时删除和增加。
- 在构造函数有个值得学习借鉴的点,就是把
-
最后就是
ProcessLifecycleOwner的介绍,主要用于实现app处于前台、后台判断的需求,同时该库使用ContentProvider是确保在Application的onCreate()之前进行初始化。