Android?Jetpack?組件LiveData源碼解析
前言
本文來(lái)分析下 LiveData 的源碼,以及其在實(shí)際開(kāi)發(fā)中的一些問(wèn)題。
基本使用
一般來(lái)說(shuō) LiveData 都會(huì)配合 ViewModel 使用,篇幅原因關(guān)于 ViewModel 的內(nèi)容將在后續(xù)博客中分析,目前可以將 ViewModel 理解為一個(gè)生命周期比 Activity 更長(zhǎng)的對(duì)象,且不會(huì)造成內(nèi)存泄漏。
示例代碼:
MainViewModel.kt
class MainViewModel: ViewModel() {
// 定義 LiveData 注意這里給了 0 作為初始值
val number = MutableLiveData<Int>(0)
fun add(){
// 相當(dāng)于 number.setValue(number.getValue() + 1)
number.value = number.value?.plus(1)
}
fun sub(){
// 相當(dāng)于 number.setValue(number.getValue() - 1)
number.value = number.value?.minus(1)
}
}
MainACtivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 獲取 ViewModel 實(shí)例
val vm = ViewModelProvider(this).get(MainViewModel::class.java)
// 調(diào)用 ViewModel 方法 進(jìn)行加法操作
bnAdd.setOnClickListener {
vm.add()
}
// 調(diào)用 ViewModel 方法 進(jìn)行減法操作
bnSub.setOnClickListener {
vm.sub()
}
// 觀(guān)察 LiveData 變化, Observer 是接口,kotlin 寫(xiě)法簡(jiǎn)化
vm.number.observe(this, Observer {
tvNumber.text = it.toString()
})
}
}
XML 非常簡(jiǎn)單就不貼了,看下效果圖:

疑問(wèn)
很簡(jiǎn)單的功能,但是有兩個(gè)問(wèn)題需要注意:
- 在 XML 中并沒(méi)有給中間的 TextView 設(shè)置 text 屬性,僅僅給 LiveData 賦值了初始值 0,就可以直接顯示到 TextView 上;
- 數(shù)值發(fā)生變化后,進(jìn)行橫豎屏切換后 TextView 依然保持著最新值(如果 number 作為普通 Int 放在 Activity 中,當(dāng) Activity 由于橫豎屏切換導(dǎo)致重建會(huì)重新變?yōu)?0);
本文將以這兩個(gè)問(wèn)題作為切入點(diǎn),對(duì) LiveData 源碼進(jìn)行分析。
源碼分析
Observer
從實(shí)例代碼中很容易看出這是典型的觀(guān)察者模式,當(dāng) LiveData 發(fā)生變化時(shí)會(huì)對(duì)其訂閱者發(fā)送通知,將最新值傳遞過(guò)去,Observer 就相當(dāng)于其觀(guān)察者,先來(lái)看一下 Observer 接口:
public interface Observer<T> {
void onChanged(T t);
}
當(dāng) LiveData 發(fā)生變化時(shí),就會(huì)觸發(fā)其觀(guān)察者的 onChanged 方法,并傳遞最新值;
再看一下其添加訂閱時(shí)的源碼:
public abstract class LiveData<T> {
//...
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 檢查是否在主線(xiàn)程
assertMainThread("observe");
// 如果觀(guān)察者所在組件的生命周期為 DESTROYED 則直接 return
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
// LifecycleBoundObserver 實(shí)現(xiàn)了 ObserverWrapper
// 理解為這是對(duì) 觀(guān)察者 Observer 的一層包裝類(lèi)即可
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// mObservers 是一個(gè) Map 容器,原始的 Observer 為 key,包裝后的 wrapper 為 value
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 同一個(gè) observer 不能在不同的生命周期組件中進(jìn)行訂閱
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
// 重復(fù)訂閱直接return
if (existing != null) {
return;
}
// LifecycleBoundObserver 利用 Lifecycle 實(shí)現(xiàn)自動(dòng)解綁
// Lifecycle 原理詳見(jiàn)我之前的博客
owner.getLifecycle().addObserver(wrapper);
}
// ...
}
從源碼中得知訂閱必須在主線(xiàn)程(這一點(diǎn)也非常適用于 Android 的 UI 更新), 訂閱后會(huì)放入一個(gè) Map 容器中存儲(chǔ);
ObserverWrapper
接著來(lái)看一下 LiveData 是如何對(duì) Observer 進(jìn)行包裝的,LifecycleBoundObserver 實(shí)現(xiàn)了 ObserverWrapper,那么就先來(lái)看看 ObserverWrapper 的源碼:
private abstract class ObserverWrapper {
final Observer<? super T> mObserver; // Observer 原始對(duì)象
boolean mActive; // 是否激活
int mLastVersion = START_VERSION; // 版本號(hào) 默認(rèn) -1
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer; // 賦值
}
abstract boolean shouldBeActive(); // 抽象方法
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) { // 如果值一樣則返回
return;
}
mActive = newActive; // 不一樣則更新 mActive
changeActiveCounter(mActive ? 1 : -1); // 記錄有多少個(gè)激活狀態(tài)的observer
// 注意這里,如果mActive是從false變更為true 則調(diào)用一次 dispatchingValue
// dispatchingValue 的源碼下面再分析
if (mActive) {
dispatchingValue(this);
}
}
}
LifecycleBoundObserver
接著看一下 LifecycleBoundObserver 的源碼:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer); // 父類(lèi)構(gòu)造器 賦值
mOwner = owner;
}
@Override
boolean shouldBeActive() { // 判斷是否是激活狀態(tài)
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 如果再 activity 中進(jìn)行 observer
// 當(dāng) activity 生命周期發(fā)生變化時(shí) 會(huì)回調(diào)到這里
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 自動(dòng)解綁
if (currentState == DESTROYED) {
// removeObserver 內(nèi)部會(huì)將 observer 從 map 容器中移除
// 并且調(diào)用其 detachObserver 方法
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
// activeStateChanged 上面已經(jīng)說(shuō)過(guò)了
// 如果 mActive 由 fasle 變更為 true 會(huì)執(zhí)行一次 dispatchingValue
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
// ...
}
MutableLiveData
上述的觀(guān)察者相關(guān)的重要源碼已經(jīng)分析完,接著來(lái)看一下示例代碼中定義的 MutableLiveData 源碼:
public class MutableLiveData<T> extends LiveData<T> {
public MutableLiveData(T value) {
super(value);
}
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
繼承自 LiveData,作用很明顯暴露出其 postValue、setValue 方法,那么就先來(lái)看一下這兩個(gè)方法調(diào)用邏輯
postValue
先來(lái)看看 postValue:
public abstract class LiveData<T> {
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
// mPendingData 默認(rèn)值為 NOT_SET
postTask = mPendingData == NOT_SET;
// 調(diào)用 postValue 后,會(huì)賦值成傳進(jìn)來(lái)的 value
mPendingData = value;
}
if (!postTask) { // 第一次調(diào)用 肯定為 true
return;
}
// 核心在于這一行,postToMainThread
// 看名字也知道是切換到主線(xiàn)程去執(zhí)行 mPostValueRunnable
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
}
ArchTaskExecutor.getInstance() 會(huì)初始化其內(nèi)部的 mDelegate 變量,其最終實(shí)現(xiàn)是 DefaultTaskExecutor;DefaultTaskExecutor 內(nèi)部包含一個(gè)主線(xiàn)程 Handler,其 postToMainThread 方法就是利用 Handler 將 runnable 發(fā)送至主線(xiàn)程執(zhí)行。這里面的源碼比較簡(jiǎn)單,就不貼出來(lái)細(xì)節(jié)了,看一下 mPostValueRunnable 具體執(zhí)行了什么:
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) { // 加鎖同步
newValue = mPendingData; // 獲取最新傳遞過(guò)來(lái)的值
mPendingData = NOT_SET; // 將 mPendingData 恢復(fù)為默認(rèn)值
}
// 最終還是調(diào)用了 setValue
setValue((T) newValue);
}
};
可以看出 postValue 可以在任意線(xiàn)程調(diào)用,最終都會(huì)被切換到主線(xiàn)程調(diào)用 setValue,但是需要注意,頻繁調(diào)用 postValue 可能會(huì)只保留最后一次的值,因?yàn)槊看?postValue 會(huì)導(dǎo)致 mPendingData 設(shè)置為新的值,但如果多次 postValue 在子線(xiàn)程執(zhí)行,但是主線(xiàn)程還沒(méi)有來(lái)得及執(zhí)行 mPostValueRunnable,會(huì)導(dǎo)致 mPendingData 沒(méi)有被恢復(fù)為 NOT_SET,那么 postTask 即為 false,但 mPendingData 會(huì)設(shè)置為最新值,當(dāng) mPostValueRunnable 執(zhí)行時(shí)從 mPendingData 中獲取的也是最新值。
setValue
postValue 內(nèi)部最終調(diào)用了 setValue,那么就來(lái)看看 setValue 的源碼:
public abstract class LiveData<T> {
static final int START_VERSION = -1;
private volatile Object mData;
private int mVersion
// 帶初始值的構(gòu)造器
public LiveData(T value) {
mData = value; // 直接給 mData 賦值
mVersion = START_VERSION + 1; //版本號(hào) +1,也就是 0
}
// 無(wú)參構(gòu)造器
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION; // 版本號(hào)默認(rèn) -1
}
protected void setValue(T value) {
// 內(nèi)部根據(jù) Looper 判斷是否在主線(xiàn)程,不在主線(xiàn)程則拋出異常
assertMainThread("setValue");
// 版本號(hào) +1
mVersion++;
// LiveData 的數(shù)據(jù),也就是被觀(guān)察的數(shù)據(jù),設(shè)置為最新值
mData = value;
// 這里是重點(diǎn)
dispatchingValue(null);
}
}
從源碼中得知,setValue 只能從主線(xiàn)程調(diào)用,內(nèi)部對(duì)版本號(hào)進(jìn)行++操作,并且設(shè)置 mData 為最新值,最終調(diào)用 dispatchingValue:
// 用于保存其觀(guān)察者 Observer,Observer 會(huì)包裝成
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) { // 默認(rèn)為 false
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true; // 進(jìn)入方法后設(shè)置為 true
do {
mDispatchInvalidated = false;
// setValue 傳進(jìn)來(lái)的是 null 不會(huì)進(jìn)入這個(gè) if
// initiator 實(shí)際上就是觀(guān)察者,如果傳遞進(jìn)來(lái)一個(gè)觀(guān)察者對(duì)象
// 則只進(jìn)行一次 considerNotify 方法調(diào)用
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else { // 遍歷自身的觀(guān)察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 調(diào)用 considerNotify 將觀(guān)察者傳入
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false; // 方法執(zhí)行結(jié)束前 設(shè)置為 false
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) { // 未激活狀態(tài)直接返回
return;
}
// 判斷是否可以是激活狀態(tài)
// LifecycleBoundObserver 中則是判斷所在組件的生命周期是否為激活狀態(tài)
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false); // 將 observer 的 mActive 設(shè)置為 fasle
return;
}
// 如果 observer 的版本號(hào) 大于 LiveData 本身的版本號(hào) 則直接返回
if (observer.mLastVersion >= mVersion) {
return;
}
// 將 observer 的版本號(hào)和 LiveData 本身的版本號(hào)同步
observer.mLastVersion = mVersion;
// 觸發(fā)其 onChanged 方法回調(diào)
observer.mObserver.onChanged((T) mData);
}
setValue 的源碼并不復(fù)雜,總結(jié)一下:
- mVersion 版本號(hào) ++ 操作,并且 mData 設(shè)置為最新數(shù)據(jù);
- dispatchingValue(null) 遍歷觀(guān)察者容器,對(duì)符合條件的觀(guān)察者調(diào)用其 onChanged 方法回調(diào)。
問(wèn)題答疑
從源碼中我們可以了解到,當(dāng)調(diào)用 LiveData.observer 時(shí),我們傳入的 observer 對(duì)象會(huì)被包裝成為 LifecycleBoundObserver,會(huì)自動(dòng)感知所在組件的生命周期;
又因?yàn)?Lifecycle 會(huì)在觀(guān)察組件生命周期之后就會(huì)進(jìn)行狀態(tài)同步,所以我們?cè)僬{(diào)用 LiveData.observer 之后會(huì)觸發(fā)一次 activeStateChanged,導(dǎo)致 observer 的 mActive 由 fasle 變?yōu)?true,所以會(huì)進(jìn)行一次 dispatchingValue;
在示例代碼中我們給 MainViewModel 中的 number 賦值了初始值 0,那么初始化時(shí)會(huì)調(diào)用 LiveData 有參的構(gòu)造函數(shù),其中對(duì) mVersion 進(jìn)行了 +1 操作,此時(shí)的 LiveData 中的 mVersion 變?yōu)榱?0,而 observer 中的 mLastVersion 為 -1,所以會(huì)進(jìn)行一次分發(fā),所以 TextView 的 text 被設(shè)置為了 0;
而第二個(gè)問(wèn)題和上述的原因類(lèi)似,不過(guò)特殊點(diǎn)在于 number 是被定義在在 ViewModel 中,開(kāi)頭也提到過(guò) ViewModel 暫時(shí)可以理解為生命周期長(zhǎng)于 Activity 的對(duì)象,那么當(dāng) Activity 由于橫豎屏切換導(dǎo)致重建后, ViewModel 中的數(shù)據(jù)并沒(méi)有清楚,LiveData 自然保持著他的 mData 最新值以及其 mVersion 版本號(hào),當(dāng) Actvitiy 重新調(diào)用 LiveData.observer 進(jìn)行訂閱時(shí),傳入的 observer 的 mVersion 已經(jīng)變?yōu)?-1,所以同樣會(huì)觸發(fā)一次 onChanged 回調(diào)得到最新值;
LiveData 特性引出的問(wèn)題
上述問(wèn)題答疑中其實(shí)可以看出 LiveData 訂閱后可以獲取最新值這在數(shù)據(jù)流中屬于粘性 事件。在示例代碼中,橫豎屏切換后仍然可以獲取最新的值,這比較符合用戶(hù)使用習(xí)慣。但實(shí)際開(kāi)發(fā)中往往有著更復(fù)雜的場(chǎng)景,比如:定義一個(gè) LiveData<Boolean>(false) 表示是否需要展示加載中彈窗,假設(shè)需求是用戶(hù)點(diǎn)擊按鈕后展示,此時(shí)用戶(hù)點(diǎn)擊按鈕,將其設(shè)置為 true,那么此時(shí) Activiy 發(fā)生重建導(dǎo)致生命周期重新走一遍,此時(shí)的 LiveData 的 value 仍然為 true,重建后用戶(hù)并沒(méi)有點(diǎn)擊按鈕但彈窗仍然會(huì)顯示;
這是一個(gè)很常見(jiàn)的業(yè)務(wù)需求,發(fā)生這種問(wèn)題的根本原因是生命周期重新走之后導(dǎo)致 observer 的 mLastVersion 變更為 -1,而 LiveData 的 mVersion 不變,導(dǎo)致重新觸發(fā) onChanged 方法回調(diào);
遇到這種情況該怎么辦呢?難道 LiveData 設(shè)計(jì)的有問(wèn)題?我認(rèn)為這并非 google 官方設(shè)計(jì)的不好,而是 LiveData 本身就應(yīng)該作用于時(shí)時(shí)刻刻需要獲取最新值的場(chǎng)景,而并非所有的數(shù)據(jù)都需要放到 ViewModel 中用 LiveData 包裹。上述的問(wèn)題更多的我認(rèn)為是 LiveData 濫用而導(dǎo)致的。 但 LiveData 的 onChanged 的數(shù)據(jù)變化后進(jìn)行回調(diào)很多場(chǎng)景使用起來(lái)又很方便,該怎么辦?
問(wèn)題解決
既然已經(jīng)知道原因,源碼又了解的差不多,很容易就能找到問(wèn)題的切入點(diǎn);那就是 considerNotify 方法中會(huì)有層層判斷,只要有一個(gè)不符合則不會(huì)觸發(fā) onChanged 方法回調(diào),可以反射修改 observer 的 mLastVersion 使其重新訂閱后仍然和 LiveData 保持一致。 不過(guò)利用到了反射,那么風(fēng)險(xiǎn)度也自然提高。
還有更好的辦法,SingleLiveData!我最初看到這個(gè)類(lèi)是在 github 中的一個(gè) issue 中,后來(lái)網(wǎng)上流傳了很多版本,其原理是對(duì) LiveData 進(jìn)行包裝,內(nèi)部定義一個(gè) HashMap<Observer<in T>, AtomicBoolean> 容器,重寫(xiě)其 observer 訂閱方法,每個(gè) observer 對(duì)應(yīng)一個(gè) AtomicBoolean 對(duì)象,在 setValue 之前先遍歷將所有的 AtomicBoolean 設(shè)置為 true,接著重寫(xiě)其 observer 包裝一層,在分發(fā)時(shí)判斷并修改 AtomicBoolean 為 false。
我覺(jué)得這也是比較好的規(guī)避問(wèn)題的方法,這里就隨便貼一個(gè)了:
class SingleLiveData<T> : MutableLiveData<T>() {
private val mPendingMap = HashMap<Observer<in T>, AtomicBoolean>()
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
val lifecycle = owner.lifecycle
if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
return
}
mPendingMap[observer] = AtomicBoolean(false)
lifecycle.addObserver(LifecycleEventObserver { source: LifecycleOwner?, event: Lifecycle.Event ->
if (event == Lifecycle.Event.ON_DESTROY) {
mPendingMap.remove(observer)
}
})
super.observe(owner) { t: T ->
val pending = mPendingMap[observer]
if (pending != null && pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
}
}
@MainThread
override fun observeForever(observer: Observer<in T>) {
mPendingMap[observer] = AtomicBoolean(false)
super.observeForever(observer)
}
@MainThread
override fun removeObserver(observer: Observer<in T>) {
mPendingMap.remove(observer)
super.removeObserver(observer)
}
@MainThread
override fun removeObservers(owner: LifecycleOwner) {
mPendingMap.clear()
super.removeObservers(owner)
}
@MainThread
override fun setValue(t: T?) {
for (value in mPendingMap.values) {
value.set(true)
}
super.setValue(t)
}
}
最后
我對(duì)于 LiveData 和網(wǎng)絡(luò)上認(rèn)為需要用 Flow 替換 LiveData 的觀(guān)點(diǎn)不同,我覺(jué)得 LiveData 和 Flow 其實(shí)應(yīng)該共存,或者說(shuō)是結(jié)合實(shí)際場(chǎng)景具體選擇,在需要綁定生命周期的場(chǎng)景下 LiveData 就是最佳選擇,沒(méi)必要強(qiáng)行使用 Flow,雖然 Flow 也提供了關(guān)聯(lián)生命周期的做法,但如果項(xiàng)目中已經(jīng)大面積使用 LiveData 真的沒(méi)必要強(qiáng)行去替換,尤其是 Java Kotlin 結(jié)合的項(xiàng)目,Java 不支持 Flow 的情況下使用 LiveData 是最佳的選擇;
以上就是Android Jetpack 組件LiveData源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Android Jetpack LiveData的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android Jetpack 狠活Lifecycles與LiveData使用詳解
- Android Jetpack組件庫(kù)LiveData源碼深入探究
- Android Jetpack組件支持庫(kù)DataBinding與ViewModel與LiveData及Room詳解
- Android開(kāi)發(fā)Jetpack組件ViewModel與LiveData使用講解
- Android開(kāi)發(fā)Jetpack組件LiveData使用講解
- Android?Jetpack庫(kù)剖析之LiveData組件篇
- 詳解Android JetPack之LiveData的工作原理
- Android Jetpack組件中LiveData的優(yōu)劣
相關(guān)文章
Android開(kāi)發(fā)之OkHttpUtils的具體使用方法
這篇文章主要介紹了Android開(kāi)發(fā)之OkHttpUtils的具體使用方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-08-08
Android 斷點(diǎn)下載和自動(dòng)安裝的示例代碼
本篇文章主要介紹了Android斷點(diǎn)下載和自動(dòng)安裝的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
詳解Android Webview加載網(wǎng)頁(yè)時(shí)發(fā)送HTTP頭信息
這篇文章主要介紹了詳解Android Webview加載網(wǎng)頁(yè)時(shí)發(fā)送HTTP頭信息的相關(guān)資料,需要的朋友可以參考下2017-05-05
淺談Android應(yīng)用安全防護(hù)和逆向分析之a(chǎn)pk反編譯
我們有時(shí)候在某個(gè)app上見(jiàn)到某個(gè)功能,某個(gè)效果蠻不錯(cuò)的,我們想看看對(duì)方的思路怎么走的,這時(shí)候,我們就可以通過(guò)反編譯來(lái)編譯該apk,拿到代碼,進(jìn)行分析。2021-06-06
Android List刪除重復(fù)數(shù)據(jù)
這篇文章主要介紹了Android List刪除重復(fù)數(shù)據(jù)的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-06-06

