手撕Jetpack組件之LiveData

LiveData是什么?

在官網(wǎng)以及網(wǎng)上有很多文章都會(huì)介紹LiveData是什么、能夠滿足什么場景以及優(yōu)勢。假若用一句話概括,它就是與EventBus有著類似功能的一個(gè)庫--事件發(fā)布訂閱機(jī)制。那么今天我們就來扒一扒它是如何實(shí)現(xiàn)的。本文將會(huì)以4個(gè)方面進(jìn)行源碼分析:

  • LiveData是如何感知生命周期的?
  • 發(fā)布者發(fā)送數(shù)據(jù)后,訂閱者是如何收到的?
  • 粘性數(shù)據(jù)是如何產(chǎn)生的以及如何避免?
  • 它與EventBus有什么區(qū)別?

簡單使用

  • 添加依賴
implementation "androidx.lifecycle:lifecycle-livedata:2.3.0"
  • 簡單demo
public class MainActivity extends AppCompatActivity {
    private MutableLiveData<String> mLiveData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 第一步
        mLiveData = new MutableLiveData<>();
        // 第二步
        mLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
            // 第四步
                Log.e("MainActivity", s);
            }
        });

    }

    public void jump(View view) {
    // 第三步
        mLiveData.setValue("Hello");
    }
}

LiveData的使用非常簡單,執(zhí)行代碼中的三個(gè)步聚,第四步就可以收到發(fā)送過來的信息。接下來分析每一步都做了一些什么事。

源碼分析

  • 構(gòu)造LiveData對(duì)象
// MutableLiveData.java
public MutableLiveData() {
    super();
}

// LiveData.java
public LiveData() {
    mData = NOT_SET;
    mVersion = START_VERSION;
}

LiveData是一個(gè)抽象類,我們創(chuàng)建的MutableLiveData是它的實(shí)現(xiàn)類。在父類的構(gòu)造方法中,初始化了兩個(gè)屬性,一個(gè)是Object類型的mData字段,它的作用是用來保存我們通過setValue傳過來的值。另一個(gè)是int類型的mVersion字段,它的初始值為0。它有什么用呢?這里暫且先埋個(gè)坑。

  • observe方法
// LiveData.java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    // owner就是我們傳過來的MainActivity,很顯然State不可能為DESTROYED
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 注釋1
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // 注釋2
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    // 注釋3
    owner.getLifecycle().addObserver(wrapper);
}

先看注釋1部分

LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

將我們的生命周期擁有者,也就是我們的MainActivity和我們在MainActivity創(chuàng)建出來的觀察者Observer包裝成了LifecycleBoundObserver,我們來看看其構(gòu)造方法做了什么事。

LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
    super(observer);
    mOwner = owner;
}

ObserverWrapper(Observer<? super T> observer) {
    mObserver = observer;
}

自己保存著我們的MainActivity的引用,調(diào)用父類ObserverWrapper構(gòu)造方法,保存我們創(chuàng)建的Observer對(duì)象。在父類里面還有一個(gè)比較重要的int類型的屬性: mLastVersion。上面有提到過mVersion字段,現(xiàn)在又來一個(gè)mLastVerison,猜測一下這兩個(gè)字段是用來判斷當(dāng)前和上一次的版本,那具體是用來判斷什么的呢?

再來看注釋2部分

ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

以我們創(chuàng)建的Observer作為key,包裝對(duì)象作為value添加到mObservers集合中,被保存到Map集合中的value還會(huì)被維護(hù)成雙向鏈表。

public V putIfAbsent(@NonNull K key, @NonNull V v) {
    Entry<K, V> entry = get(key);
    if (entry != null) {
        return entry.mValue;
    }
    put(key, v);
    return null;
}

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;

}

再來看注釋3部分

// 這行代碼就使得LiveData可以感知Activity的生命周期
owner.getLifecycle().addObserver(wrapper);

看到這里就明白了LiveData是如何感知Activity的生命周期了。將LifecycleBoundObserver作為生命周期的觀察者,這樣在生命周其變化時(shí)就會(huì)回調(diào)到onStateChanged方法。addObserver方法源碼分析可以看手撕Jetpack組件之Lifecycle

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        if (currentState == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }
    ...
}
  • setValue
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

記得在上文中有提到過mVersion這個(gè)字段,初始值為0,此時(shí)變成了1,我們傳的數(shù)據(jù)被mData引用。繼續(xù)跟進(jìn):

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

因在setValue方法中傳入的ObserverWrappernull,所以會(huì)進(jìn)入到else條件里面去。上文有提到過生命周期持有者與我們創(chuàng)建的Observer被包裝成LifecycleBoundObserver對(duì)象,然后又以Observer為key,這個(gè)包裝對(duì)象為value添加到mObservers集合中。繼續(xù)跟進(jìn)considerNotify方法。

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
    //
    // we still first check observer.active to keep it as the entrance for events. So even if
    // the observer moved to an active state, if we've not received that event, we better not
    // notify for a more predictable notification order.
    // 注釋4
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 注釋5
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    // 注釋6
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

先看注釋6部分,observer.mObserver指的就是我們在MainActivity里面創(chuàng)建的Observer,所以訂閱者就收到了數(shù)據(jù)。

注釋4和注釋5是用來阻止數(shù)據(jù)回調(diào)的判斷條件。先看注釋4

// LifecycleBoundObserver
@Override
boolean shouldBeActive() {
    return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

LifecycleOwner的狀態(tài)決定返回值,因?yàn)檫@里的mOwner就是我們的MainActivity,此時(shí)我們是在setValue的操作,狀態(tài)已經(jīng)變成RESUMED,所以這里返回true。注釋4的if語句內(nèi)不會(huì)執(zhí)行。

再看注釋5部分,這兩個(gè)屬性在上文中多次提到,原來它們的作用是用來判斷是否要回調(diào)觀察察者的回調(diào)方法。mLastVersion初始值為-1,mVersion的值在setValue時(shí)已經(jīng)變成1了,所以注釋5的條件也不成立。

到這里,整個(gè)源碼分析就已經(jīng)完畢。我們再來看看其它API的調(diào)用。

  • postValue
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

源碼看起來比較簡單。就是往主線程提交了一個(gè)Runnable

private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

最終還是調(diào)到了setValue。這兩者的唯一區(qū)別就是setValue只能在主線程,postValue不受線程局限。

  • observeForever

該方法添加的Observer并不受Activity的生命周期所約束。也就是說,當(dāng)我們在Activity的onCreate方法注冊一個(gè)觀察者時(shí),若沒有在onDestroy方法中手動(dòng)移除這個(gè)觀察者,當(dāng)Activity被銷毀后,這個(gè)觀察者仍然可以收到消息的回調(diào)。它是如何做到的?來看看其源碼實(shí)現(xiàn)。

@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    // 這里與observe方法一樣,將我們傳進(jìn)來的observer包裝成一個(gè)wrapper對(duì)象
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    // 將其放入到mObservers這個(gè)集合中
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing instanceof LiveData.LifecycleBoundObserver) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    wrapper.activeStateChanged(true);
}

void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    mActive = newActive;
    changeActiveCounter(mActive ? 1 : -1);
    if (mActive) {
    // 看到我們上面分析過了的方法。不過這里的參數(shù)為上面的AlwaysActiveObserver
        dispatchingValue(this);
    }
}

由于dispatchingValue方法的參數(shù)不為空,所以會(huì)進(jìn)入這個(gè)方法的if語句中,最終就會(huì)執(zhí)行到上面提到的注釋4部分。由于我們的觀察者是被包裝了AlwaysActiveObserver對(duì)象,注釋4部分的if條件判斷語句由這個(gè)類實(shí)現(xiàn)。

@Override
boolean shouldBeActive() {
    return true;
}

這里它是直接返回了true,這也就使得它在沒有被手動(dòng)移除時(shí),即使Activity銷毀了仍然可以收到消息的原因。而我們前面提到LifecycleBoundObserver,它實(shí)現(xiàn)這個(gè)方法是由當(dāng)前Activity的生命周期的State來決定的。

粘性事件

在開發(fā)中共用同一個(gè)LiveData是非常常見的,但隨之也會(huì)產(chǎn)生一個(gè)副作用,數(shù)據(jù)粘性。也就是說,新注冊一個(gè)觀察者的時(shí)候,仍然可以收到上個(gè)觀察者訂閱的數(shù)據(jù)。比如我們在A界面跳轉(zhuǎn)到B界面,在跳轉(zhuǎn)之前,先用LiveData#setValue一個(gè)值,此時(shí)在B界面的onCreate方法用同一個(gè)LiveData對(duì)象注冊一個(gè)觀察者,居然收到了上個(gè)界面發(fā)送來的數(shù)據(jù)。一般情況下,我們是不希望收到上個(gè)界面的數(shù)據(jù)的,那這產(chǎn)生的原因是什么呢?

在上文有多次提到過,LiveData有兩個(gè)比較重要的屬性:Object類型的mDataint類型的mVersion,分別記錄setValue發(fā)過來的數(shù)據(jù)和類似某種計(jì)數(shù)機(jī)制數(shù)據(jù)發(fā)送的次數(shù),每調(diào)用一次setValue,這個(gè)次數(shù)都會(huì)++。

界面AsetValue之后,此時(shí)LiveData中的mData保存著數(shù)據(jù),mVersion為1。打開界面B,因?yàn)槭窃诮缑鍮的onCreate方法內(nèi)用LiveData注冊了一個(gè)新Observer,根據(jù)上文提到LiveData感知生命周期部分,會(huì)執(zhí)行到LifecycleBoundObserver#onStateChanged方法

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        if (currentState == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }
    ...
}

最終會(huì)執(zhí)行到上文提到的注釋5部分代碼。因?yàn)樵趧?chuàng)建一個(gè)新LifecycleBoundObserver時(shí),它的mLastVersion屬性值-1,所以注釋5部分的if條件語句不成立,所以就會(huì)執(zhí)行到注釋6部分。這就是收到了上一個(gè)訂閱者的數(shù)據(jù)原因。

如何避免這個(gè)問題了?

從理論上來分析,每個(gè)界面都使用自己的LiveData,每次都創(chuàng)建一個(gè)新LiveData對(duì)象。但由于在實(shí)際開發(fā)中,數(shù)據(jù)共享是非常常見的需求,所以這種方式并不是很完美。

通過上文的分析,在注釋4和注釋5這兩個(gè)條件語句任意滿足的話都可攔截訂閱者收到發(fā)布者發(fā)布的數(shù)據(jù)。根據(jù)比較,注釋5這個(gè)點(diǎn)是相對(duì)比較容易hook的。通過反射,在新注冊Observer時(shí),把其包裝對(duì)象LifecycleBoundObserver中的mLastVersion改成與當(dāng)前LiveData中的mVersion一樣的值就可以了。

思路分析:

  • 想要修改mLastVersion字段,就需要先獲取LifecycleBoundObserver字節(jié)碼對(duì)象
  • 由于LifecycleBoundObserver是被保存在集合中,所以需要先獲取mObservers字節(jié)碼對(duì)象
  • 獲取mObservers就需要先獲取LiveData的字節(jié)碼對(duì)象
public class CustomLiveData<T> extends MutableLiveData<T> {


    @Override
    public void observe(@NonNull @NotNull LifecycleOwner owner, @NonNull @NotNull Observer<? super T> observer) {
        super.observe(owner, observer);
        try {
            hook((Observer<T>) observer);
        } catch (Exception e) {
            Log.e("CustomLiveData", "observe exception: " + e.getMessage());
        }

    }

    private void hook(Observer<T> observer) throws Exception {
        Class<LiveData> liveDataClass = LiveData.class;
        Field mObserversField = liveDataClass.getDeclaredField("mObservers");
        mObserversField.setAccessible(true);
        Object mObservers = mObserversField.get(this);
        // 因?yàn)樵贛ap中獲取value時(shí)是通過get方法獲取,所以還需要拿到這個(gè)get方法的字節(jié)碼對(duì)象
        Method getMethod = mObservers.getClass().getDeclaredMethod("get", Object.class);
        getMethod.setAccessible(true);
        // 我們傳進(jìn)來的Observer被作為key,與LifecycleBoundObserver存入到mObservers中
        Object entry = getMethod.invoke(mObservers, observer);
        // LifecycleBoundObserver
        Object lbo = null;
        if (entry instanceof Map.Entry) {
            lbo = ((Map.Entry) entry).getValue();
        }
        if (lbo == null) {
            throw new NullPointerException("observerWrapper為空");
        }
        // mLastVersion是在父類中,先獲取父類ObserverWrapper字節(jié)碼對(duì)象
        Class<?> observerWrapperClass = lbo.getClass().getSuperclass();
        Field mLastVersionField = observerWrapperClass.getDeclaredField("mLastVersion");
        mLastVersionField.setAccessible(true);

        Field mVersionField = liveDataClass.getDeclaredField("mVersion");
        mVersionField.setAccessible(true);
        Object mVersionValue = mVersionField.get(this);

        mLastVersionField.set(lbo, mVersionValue);
    }
}

該解決方案參考Android消息總線的演進(jìn)之路:用LiveDataBus替代RxBus、EventBus

之前有用過美團(tuán)的這個(gè)LiveDataBus這個(gè)庫,但發(fā)現(xiàn)一個(gè)問題就是短時(shí)間內(nèi)發(fā)送多個(gè)事件給同一個(gè)Observer會(huì)出現(xiàn)只收到一個(gè)。

上面的方案使用的是反射,我們還可以使用一個(gè)包裝類來實(shí)現(xiàn)。

public class ObserverWrapper<T> implements Observer<T> {
    private final StickyLiveData<T> mLiveData;
    private final Observer<T> mObserver;
    private final boolean isSticky;
    private int mLastVersion;

    public ObserverWrapper(StickyLiveData<T> stickyLiveData, Observer<T> observer, boolean isSticky) {
        mLiveData = stickyLiveData;
        mObserver = observer;
        this.isSticky = isSticky;
        mLastVersion = mLiveData.getVersion();
    }

    @Override
    public void onChanged(T t) {
        if (mLastVersion >= mLiveData.getVersion()) {
            // //但如果當(dāng)前observer它是關(guān)心 黏性事件的,則給他。
            if (isSticky && mLiveData.getStickyData() != null) {
                mObserver.onChanged(mLiveData.getStickyData());
            }
            return;
        }
        mLastVersion = mLiveData.getVersion();
        mObserver.onChanged(t);
    }
}
public class StickyLiveData<T> extends LiveData<T> {
    private T mStickyData;
    private int mVersion = 0;
    private final OnDestroyCallback mCallback;

    public interface OnDestroyCallback {
        void onDestroy();
    }

    public StickyLiveData(@NonNull OnDestroyCallback callback) {
        this.mCallback = callback;
    }

    @Override
    protected void setValue(T value) {
        mVersion++;
        super.setValue(value);
    }

    @Override
    protected void postValue(T value) {
        mVersion++;
        super.postValue(value);
    }

    public void setStickyData(T stickyData) {
        this.mStickyData = stickyData;
        setValue(stickyData);
    }

    public void postStickyData(T stickyData) {
        this.mStickyData = stickyData;
        postValue(stickyData);
    }

    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        observeSticky(owner, observer, false);
    }

    public void observeSticky(LifecycleOwner owner, Observer<? super T> observer, boolean isSticky) {
        super.observe(owner, new ObserverWrapper(this, observer, isSticky));
        owner.getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    mCallback.onDestroy();
                }
            }
        });
    }

    public T getStickyData() {
        return mStickyData;
    }

    public int getVersion() {
        return mVersion;
    }
}
public class LiveDataBus {
    private final ConcurrentHashMap<String, StickyLiveData> mHashMap = new ConcurrentHashMap<>();
    private static final SingletonHelper<LiveDataBus> INSTANCE =
            new SingletonHelper<LiveDataBus>() {
                @Override
                protected LiveDataBus create() {
                    return new LiveDataBus();
                }
            };

    public static LiveDataBus get() {
        return INSTANCE.get();
    }


    public <T> StickyLiveData<T> with(String eventName) {
        StickyLiveData liveData = mHashMap.get(eventName);
        if (liveData == null) {
            liveData = new StickyLiveData<>(new StickyLiveData.OnDestroyCallback() {

                @Override
                public void onDestroy() {
                    mHashMap.remove(eventName);
                }
            });
            mHashMap.put(eventName, liveData);
        }
        return liveData;
    }
}
public abstract class SingletonHelper<T> {

    public SingletonHelper() {
    }


    private T mInstance;

    protected abstract T create();


    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

這個(gè)庫 UnPeek-LiveData也是處理LiveData粘性事件的,有興趣的也可以去查看。

與EventBus的區(qū)別

  • LiveData可以自動(dòng)感知Activity/Fragment的生命周期,EventBus做不到。
  • EventBus需要手動(dòng)取消事件的注冊,LiveData不需要。
  • LiveData是通過接口回調(diào)的方式通知訂閱者,EventBus通過反射找到標(biāo)有其注解的方法通知訂閱者。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容