对 LiveData 的源码分析

Q: Activity 中使用 LiveData 时,是如何保证内存不泄漏的?
A: 很简单,调用 LiveData.observe 来进行监听时,observe 方法内会添加一个 Activity.onDestroy 的监听。
当 Activity.onDestroy 触发时,LiveData 会 detachObserver 清空所有观察者。

Q: LiveData 的生命周期直到 Activity.onDestroy 时结束吗?
A: 是的,但需要注意的是 LiveData 并不是直接被 Activity 持有,它用于绑定 Activity.onDestroy 监听和 LiveData.observe 中传入的监听回调,LiveData 也不持有 监听回调,实际持有回调引用的是
LiveData 的内部类 LifecycleBoundObserver,这个内部类正是 Activity.onDestroy 的监听类。即GC的引用链为 Activity -> LiveData.LifecycleBoundObserver -> Activity中的LiveData监听
总结下职责就是:
LiveData 负责绑定 LifecycleBoundObserver、Activity.onDestroy、Activity中的LiveData监听 三者,使 LifecycleBoundObserver 可以在 Activity.onDestroy 时释放 Activity中的LiveData监听

Q: LiveData 是如何通过 postValue 或 setValue 来触发回调的?
A: postValue 和 setValue 最终都会调用到 dispatchingValue 方法,此方法会调用 considerNotify 来发送通知,
dispatchingValue 负责通知 LifecycleBoundObserver 有事件触发了,而 considerNotify 负责判断此事件是否应当触发 Activity中的LiveData监听。

Q: LiveData 是如何做到 只在页面显示时通知,在页面隐藏时不通知的?
A: LiveData.considerNotify 方法中通过进行了判断,仅当 LifecycleBoundObserver.mActive 为 true 时才能继续向下走,为 false 时会立即中断函数。
这个 mActive 标记了 页面是否在活动状态,它是在什么时候更新的呢? 每当 Activity 的页面状态改变,Lifecycle 就会触发 onStateChanged,进而调用 activeStateChanged 方法来更新 mActive。
onStateChange 调用 activeStateChanged 时会传入 shouldBeActive() 方法的返回值,这个返回值正是新的 active,shouldBeActive 内部很简单:当 Activity 的 currentState >= Started 时返回 true
这里可能会引起误会:STARTED?那就是 Start、Resume、Pause、Stop 的那个 Start 咯,那么 Stop 就会返回true了,那么页面切换时 active 应该一直是 true,那就很奇怪啊。
其实他这里的 STARTED 是 State.STARTED,而上面想到的 Stop 是 Event.ON_STOP,一个是状态、一个是事件,两者不同的,比 State.STARTED 大的状态只有一个 State.RESUMED,
所以只有在这两个状态时 active 为 true,也只有在这两种状态下,LiveData.considerNotify 才会触发 Activity中的LiveData监听。

Q: LiveData 是如何做到 在页面隐藏时发送通知后,会在页面显示时即时更新通知呢?
A: 上面讲到,页面状态改变会触发 LifecycleBoundObserver 中的 onStateChange 方法,进而通过 activeStateChanged 来更新 mActive,而即时更新的代码快就摆在这个 activeStateChanged 中。
activeStateChanged 简单判断了一下是否调用 onActive、onInactive 后,会在 mActive == true 时调用 dispatchingValue 来通知事件,调用 dispatchingValue 时传入了一个参,
这表示仅对传入的这个参数进行事件通知。dispatchingValue 通过 considerNotify 进行通知,而 considerNotify 判断 mActive == true 所以就成功触发了 Activity中的LiveData监听。

Q: 不对呀,如果按你说的,一旦发现页面显示就通知监听,那么每次页面显示就都会触发监听,监听就会重复触发,那不就乱了么?
A: considerNotify 函数内有一个判断用于解决你说的重复触发监听问题,它会比较 LifecycleBoundObserver.mLastVersion 的版本是否与 LiveData.mVersion 相同,只有当判断为需要更新时才会触发监听。
LiveData.postValue 会切换线程调用 setValue,而 setValue 中会让 mVersion++ ,即每次修改值,都会导致版本增加。
LiveData.considerNotify 中触发监听时,会更新 LifecycleBoundObserver.mLastVersion = mVersion,即每次成功的触发监听,都会导致版本号同步。
LiveData 就是用这种方式来让监听只会更新一次,成为最新的值。

Q: 你一直说的 LifecycleBoundObserver 和 LiveData 是个什么关系?
A: LiveData 代表一个值,LifecycleBoundObserver 代表这个值的每一个监听者。
1、LifecycleBoundObserver 是 LiveData 的普通内部类,所以隐性持有 LiveData对象。
2、LiveData 通过 mObservers 来存放所有的 LifecycleBoundObserver。
3、每次调用 LiveData.observe 都会新建一个 LifecycleBoundObserver,并绑定它和监听,实现 Activity.onDestroy 时释放监听的功能。
4、一旦移除监听(removeObserver),会连同 LifecycleBoundObserver 一起移除,这样才能彻底丢弃监听引用。
5、Activity 的状态变化,首个通知的是 LifecycleBoundObserver 而不是 LiveData,LifecycleBoundObserver 才是实现 LifecycleObserver 接口的生命周期观察者
6、页面显示时立即更新值 这个功能是通过 LifecycleBoundObserver 对生命周期的监听方法开始的。
7、LiveData 有一个版本号,而每一个 LifecycleBoundObserver 都有一个版本号,这保证了一旦值更新,每一个 LifecycleBoundObserver 都能正确的更新成最新的值,也能只触发一次监听。

你可能感兴趣的:(Android)