【Android JetPack系列】LiveData

1、前言

一、什麼是 LiveDatagit

LiveData 是一個數據持有類。它具備如下特色:github

  • 數據能夠被 觀察者 訂閱;
  • 可以感知組件( Fragment、Activity、Service ) 的生命週期;
  • 只有在 組件 處於 激活狀態纔會通知觀察者有數據更新;

二、LiveData 能爲咱們作什麼安全

  • 可以保證 數據 和 UI 統一LiveData 採用了 觀察者模式,LiveData 是被觀察者,當數據有變化時會通知 UI架構

  • 減小內存泄露LiveData 可以感知到組件的生命週期,當組件處於 銷燬(destroyed) 狀態時,觀察者對象會被清除,當 Activity 中止時不會致使 crash ,由於 組件處於非激活狀態時,不會收到 LiveData中數據變化的通知。app

  • 組件和數據相關的內容可以實時更新。組件在前臺的時候可以實時收到數據改變的通知,當組件從後臺切換到前臺時,LiveData 可以將最新的數據通知組件,所以保證了組件中和數據相關的內容可以實時更新。ide

  • 解決橫豎屏切換(configuration change)數據問題。在屏幕發生旋轉時,不須要額外的處理來保存數據,當屏幕方向變化時,組件會被 recreate,然而系統並不能保證你的數據可以被恢復。當採用 LiveData 保存數據時,由於數據和組件分離了,當組件被 recreate ,數據仍是存在 LiveData 中,並不會被銷燬。源碼分析

  • 資源共享。若是對應的 LiveData 是單例的話,就能在 App 的組件間分享數據;這部分詳細的信息能夠參考 繼承 LiveDatapost

2、簡單使用

一、建立LiveData

LiveData 的2種建立方式:this

  • 直接使用MutableLiveData對象;
  • 自行繼承 LiveData 類。

1.一、直接使用 MutableLiveDataspa

MutableLiveData<String> data = new MutableLiveData<>();

1.二、繼承 LiveData

二、建立並訂閱觀察者

LiveData 經過 observe()方法註冊觀察者。觀察者這裏使用匿名方式:

// 寫於MainActivity
data.observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                Toast.makeText(MainActivity.this,s,Toast.LENGTH_SHORT).show();
            }
        });

Observe() 源碼分析:

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        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;
        }
        owner.getLifecycle().addObserver(wrapper);
    }

observe方法接收 2 個參數:

  • 一個是具備生命週期的 LifecycleOwner;
  • 另外一個是觀察者 Observer<T>.

首先判斷 LifecycleOwner 當前的生命週期是否爲 Destroyed

  • 若是是則直接 return
  • 若是不等於Destroyednew 了一個內部類 LifecycleBoundObserver 對象而且構造方法傳入了具備生命週期的 LifecycleOwner和 觀察者。看下源碼:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

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

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

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

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

LifecycleBoundObserver 繼承自 ObserverWrapper,並實現 GenericLifecycleObserver,而 GenericLifecycleObserver 繼承了 LifecycleObserver接口。

由此能夠看出LifecycleBoundObserver類就是把Observer 和生命週期關聯起來。

再看此類,咱們先看 onStateChanged()方法,當生命週期變化時會回調,若是getCurrentState() == DESTROYEDremoveObserver,反之則調用父類ObserverWrapperactiveStateChanged()方法:

private abstract class ObserverWrapper {
        final Observer<T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

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

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

分析activeStateChanged():

  • 首先判斷 activeState新舊狀態是否相同,不一樣則把新的狀態賦給 mActive,是生命週期狀態處於ACTIVE狀況下的邏輯處理。若是新的狀態和舊的狀態相同則直接返回。

  • 這裏有個常量 LiveData.this.mActiveCount,看註釋能夠理解爲觀察者處於活動狀態 個數。

  • 往下看 if (wasInactive && mActive)。 若是 mActiveCount=0 而且 mActivetrue,即觀察者處於活動狀態。

    • 個數從 0 變爲 1 個則調用 onActive(); 觀察者處於活動狀態
    • 個數從1 變爲 0 時則調用 onInactive()

然而onActive()onInactive()並無任何實現代碼。好了,接下來繼續往下看dispatchingValue(this);應該就是數據變化消息調度。源代碼:

private 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<T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

前面的幾行if 判斷姑且先不看,先看從if(initiator != null)開始看,若是initiator!= null調用considerNotify(initiator)方法;源代碼:

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.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

最後一行代碼 observer.mObserver.onChanged((T) mData); Observer的數據變化回調;

好了咱們再回過頭看看initiator == null的邏輯:

for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }

若是initiator == null 則會經過迭代器mObservers 遍歷獲取 ObserverWrapper,最終仍是調用 considerNotify 方法;既然有取 ObserverWrapper,咋們再看看在哪兒存的:

回到 Observe() 方法中:

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        
    
        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;
        }
        owner.getLifecycle().addObserver(wrapper);
    }

mObservers.putIfAbsent(observer, wrapper) 存入容器中,mObservers.putIfAbsent 這個添加數據的方式貌似不多見,因而乎在看看 mObservers是個什麼數據容器,成員變量中:

private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers =
        new SafeIterableMap<>();

SafeIterableMap 有如下特性:

  • 支持鍵值對存儲,用鏈表實現,模擬成 Map 的接口
  • 支持在遍歷的過程當中刪除任意元素,不會觸發ConcurrentModifiedException
  • 非線程安全

最後 addObserver 添加註冊。

三、發起數據通知

發起數據通知 2 種方式:

  • postValue
  • setValue
data.postValue("Hello LiveData");
 // data.setValue("Hello LiveData");

MutableLiveData源碼:

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
       super.postValue(value);
    }

   @Override
   public void setValue(T value) {
       super.setValue(value);
   }
 }

咱們先看看setValue 代碼:

@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
private static void assertMainThread(String methodName) {
        if (!ArchTaskExecutor.getInstance().isMainThread()) {
            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
                    + " thread");
        }
    }

assertMainThread("setValue");則是判斷是否在主線程。

因此貌似**setValue 方式必須在主線程中執行,若是非主線程則拋出異常。 **

再看看postValue:

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

postValue調用postToMainThread方法,最終仍是用過setValue方式:

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

所以最終明白爲何 setValue 方法只能在主線程中調用,postValue 能夠在任何線程中調用,若是是在後臺子線程中更新 LiveData的值,必須調用postValue

3、高級應用

一、 LiveDataBus 的設計和架構

LiveDataBus源碼

LiveDataBus 的組成

  • 消息 消息能夠是任何的Object,能夠定義不一樣類型的消息,如BooleanString。也能夠定義自定義類型的消息。

  • 消息通道
    LiveData扮演了消息通道的角色,不一樣的消息通道用不一樣的名字區分,名字是String類型的,能夠經過名字獲取到一個LiveData消息通道。

  • 消息總線
    消息總線經過單例實現,不一樣的消息通道存放在一個HashMap中。

  • 訂閱
    訂閱者經過getChannel獲取消息通道,而後調用observe訂閱這個通道的消息。

  • 發佈
    發佈者經過getChannel獲取消息通道,而後調用setValue或者postValue發佈消息。

相關文章
相關標籤/搜索