Android框架式編程之LiveData


一、LiveData 介紹

LiveData是 Google 推薦的 Android 架構組件之一,是一個基於觀察者模式的數據容器,但與一般的被觀察者不同的是,它是有生命周期感知功能,解決了Android開發者需要去手動處理生命周期的痛點。

它具備如下特點:

① 數據可以被觀察者訂閱。

② 能夠感知組件(Fragment、Activity、Service)的生命周期。

③ 只有當組件處於活躍狀態(STARTED或RESUMED)時才會通知觀察者數據發生了變化。

官方對其優點說明概括如下:

① UI和實時數據保持一致
因為LiveData采用了觀察者模式,LiveData是被觀察者,所以當數據有變化時觀察者(UI)就會獲得通知,並進行更新。

② 避免內存泄漏
當被綁定的組件處於DEDTROYED狀態時,觀察者對象會自動清理自身的數據。

③ 當Activity停止時不會引起崩潰
當組件處於非激活狀態時,它不會收到任何LiveData中數據變化的通知。

④ 不需要額外的處理來響應生命周期的變化
LiveData可以自動感知被綁定的UI組件的生命周期,只有當UI組件處於活躍狀態時才會通知數據變化。

⑤ 始終保持最新的數據
當組件從不活躍狀態變為活躍狀態時總是可以收到最新的數據

⑥ 解決了Configuration change問題
當Activity或Fragment由於配置變化(如用戶旋轉了設備屏幕)而被重新創建時,能夠立刻收到最新的數據。

⑦ 資源共享
我們可以實現一個單例模式的LiveData子類,並將系統服務封裝在該類中。這樣,任何需要這些系統服務的觀察者就可以通過觀察這個LiveData子類對象實現資源的共享。

二、LiveData的使用

LiveData組件相關的類和接口有:LiveData類、Observer接口、GenericLifecycleObserver接口和LifecycleOwner接口。

1. LiveData是個抽象類,MediatorLiveData繼承自MutableLiveData,MutableLiveData則繼承自LiveData。MediatorLiveData可以看成是多個LiveData的代理,MutableLiveData則是提供了可以修改LiveData中數據的對外公開方法。

2. LiveData有3個內部類ObserverWrapper、AlwaysActiveObserver和LifecycleBoundObserver,其中后兩個類都是ObserverWrapper的子類。LifecycleBoundObserver實現了GenericLifecycleObserver接口,當LifecycleOwner的生命周期變化時就會通過該接口的onStateChanged()方法回調回來。

3. Observer接口就是觀察者,它定義了LiveData數據變化的回調方法onChanged()。MediatorLiveData的內部類Source實現了該接口。

使用步驟如下:

1. 創建一個持有某種數據類型的LiveData對象。

2. 創建一個觀察者對象,通常在UI Controller(如Activity或Fragment)中創建這個觀察者。

3. 將觀察者對象作為參數傳入LiveData.observe()方法,連接觀察者和LiveData。

2.1 創建LiveData對象

public class NameViewModel extends ViewModel {
    // Create a LiveData with a String
    private MutableLiveData<String> mCurrentName;
    public MutableLiveData<String> getCurrentName() {
          if (mCurrentName == null) {
              mCurrentName = new MutableLiveData<String>();
          }
          return mCurrentName;
    }
    // Rest of the ViewModel...
}

2.2 觀察LiveData對象

通常情況下都是在組件的onCreate()方法中開始觀察數據,原因有以下兩點:

① 系統會多次調用onResume()方法

② 確保Activity或Fragment在處於活躍狀態時立刻可以展示數據。

public class NameActivity extends AppCompatActivity {

    private NameViewModel mModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Other code to setup the activity...
        // Get the ViewModel.
        mModel = ViewModelProviders.of(this).get(NameViewModel.class);
        // Create the observer which updates the UI.
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {
                // Update the UI, in this case, a TextView.
                mNameTextView.setText(newName);
            }
        };
        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        mModel.getCurrentName().observe(this, nameObserver);
    }
}

2.3 更新LiveData對象

LiveData 沒有提供可用的公共方法來更新其持有的數據,但是如果我們使用LiveData的子類MutableLiveData來存儲數據,那么我們就可以使用它的公共方法setValue()postValue()方法更新數據。

mButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        String anotherName = "John Doe";
        mModel.getCurrentName().setValue(anotherName);
    }
});

2.4 繼承LiveData類

當然我們也可以通過繼承LiveData定義自己的擴展類:

public class StockLiveData extends LiveData<BigDecimal> {
private StockManager mStockManager; private SimplePriceListener mListener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; public StockLiveData(String symbol) { mStockManager = new StockManager(symbol); } @Override protected void onActive() { mStockManager.requestPriceUpdates(mListener); } @Override protected void onInactive() { mStockManager.removeUpdates(mListener); } } public class MyFragment extends Fragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); LiveData<BigDecimal> myPriceListener = ...; myPriceListener.observe(this, price -> { // Update the UI. }); } }

自定義的StockLiveData實現了LiveData中的空方法onActive()onInactive()

三、LiveData 的原理

3.1 數據發生變化時LiveData如何通知 Observer?

LiveData提供了兩種添加觀察者的方法:observe()observeForever()

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {

    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }

    //將LifecycleOwner對象和Observer對象封裝成LifecycleBoundObserver對象
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // mObservers是一個SafeIterableMap類型的數據容器,通過它的putIfAbsent()方法可以判斷Observer對象是否已經與一個LifecycleBoundObserver對象關聯
    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);
}

@MainThread
public void observeForever(@NonNull Observer<T> observer) {
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
        throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    wrapper.activeStateChanged(true);
}

如果通過observeForever()方法添加觀察者,那么觀察者會一直收到數據變化的回調通知;

如果通過observe()方法添加,那么觀察者只會在LifecycleOwner處於STARTED和RESUMED即active狀態才會收到。

其中observe()方法內部使用了LifecycleBoundObserver類,observeForever()方法內部則使用了AlwaysActiveObserver類,它們都是抽象類ObserverWrapper的具體實現類。

所以,我們先來看一下這個抽象類:

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

    ......

    void activeStateChanged(boolean newActive) {
        //新狀態和之前狀態相同則不做任何處理
        if (newActive == mActive) {
            return;
        }
        // 將當前狀態設置為傳入的newActive
        mActive = newActive;
        //處於active狀態的觀察者數量是否為0
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        //如果當前狀態為active狀態,則處於active狀態的觀察者數量加1,否則減1
        LiveData.this.mActiveCount += mActive ? 1 : -1;
        //處於active狀態的觀察者個數從0變為1,回調LiveData的onActive()方法
        if (wasInactive && mActive) {
            onActive();
        }
        //處於active狀態的觀察者數量從1變為0,回調LiveData的onInactive()方法
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

ObserverWrapper是Observer的封裝類,在Observer的基礎上增加了 mActive 和 mLastVersion 。其中mActive 用來標識觀察者是否活躍,即它是否處於可用的生命周期內。

onActiveStateChanged()方法定義了觀察者在活躍狀態和非活躍狀態之間轉換時的處理邏輯,如果ObserverWrapper對象處於活躍狀態,那么LiveData中的mActiveCount 計數會加一,否則會減一。緊接着,onActive()方法會在mActiveCount為1時觸發,onInactive()方法則會在mActiveCount為0時觸發。最后,如果ObserverWrapper對象處於活躍狀態,還會調用 dispatchingValue()方法發送新的數據。

private void dispatchingValue(@Nullable ObserverWrapper initiator) {

    //如果mDispatchingValue為true,則將mDispatchInvalidated設為true並直接返回
    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;
}

其中,mDispatchingValue和mDispatchInvalidated變量是為了防止重復分發。該方法會循環遍歷mObservers 這個集合,並通過調用considerNotify()方法為每一個處於活躍狀態且數據未更新的觀察者發送數據。

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

現在我們再來分析LifecycleBoundObserver類和AlwaysActiveObserver類。我們先看LifecycleBoundObserver:

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {

    @NonNull final LifecycleOwner mOwner;

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

     //判斷是否處於active狀態
    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    //當LifecycleOwner生命周期發生變化時會回調該方法
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        //如果當前處於DESTROYED狀態,則會自動移除觀察者
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        //調用ObserverWrapper的activeStateChanged()方法,將當前是否處於active狀態的判斷結果作為參數傳入
        activeStateChanged(shouldBeActive());
    }

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

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

可以看出,LifecycleBoundObserver 把 ObserverWrapper 和 Lifecycle 結合在了一起。因此LiveData就可以獲取到觀察者的生命周期,當觀察者的生命周期可用時,LiveData 會把數據發送給觀察者,而當觀察者生命周期不可用的時,即owner.getLifecycle().getCurrentState() == DESTROYED ,LiveData 就選擇不發送並且自動解綁,防止內存泄漏。

AlwaysActiveObserver顧名思義觀察者的生命周期一直可用,所以它和LifecycleOwner的生命周期無關,當數據改變時不管LifecycleOwner處於什么狀態都會收到回調通知,除非手動將這個觀察者移除。從AlwaysActiveObserver的源碼也可以看出,它通過shouldBeActive()方法將自己的生命周期設為一直可用,LiveData的observeForever()方法內部使用的就是AlwaysActiveObserver。

private class AlwaysActiveObserver extends ObserverWrapper {

    AlwaysActiveObserver(Observer<T> observer) {
        super(observer);
    }

    @Override
    boolean shouldBeActive() {
        return true;
    }
}

3.2 LiveData中的數據如何更新?

那么怎么改變LiveData中持有的數據呢?LiveData提供了兩種方法——postValue()setValue()

@MainThread
protected void setValue(T value) {
    //判斷當前線程是否是主線程,不是主線程就拋出異常
    assertMainThread("setValue");
    //版本更新
    mVersion++;
    //改變LiveData持有的數據
    mData = value;
    //將新的數據分發給訂閱該LiveData所有的觀察者們
    dispatchingValue(null);
}

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask)  return;
    //在主線程中執行mPostValueRunnable中的內容
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

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

它們的區別是setValue()方法要在主線程中調用,而postValue()方法既可在主線程也可在子線程中調用。這是因為postValue()方法則通過ArchTaskExecutor將mPostValueRunnable運行在主線程,而在mPostValueRunnable中最終會調用setValue()方法來實現改變LiveData存儲的數據。

但是我們發現LiveData並沒有將這兩個方法對外公開,好在我們可以通過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);
    }
}

LiveData還有一個子類MediatorLiveData,它可以看成多個LiveData的代理。它定義了一個內部類Source,用於封裝LiveData和Observer,這樣如果多個LiveData被添加到MediatorLiveData中,那么任何一個LiveData數據發生變化時,MediatorLiveData的觀察者都會收到通知。Source的源碼如下:

private static class Source<V> implements Observer<V> {
    final LiveData<V> mLiveData;
    final Observer<V> mObserver;
    int mVersion = START_VERSION;

    Source(LiveData<V> liveData, final Observer<V> observer) {
        mLiveData = liveData;
        mObserver = observer;
    }

    void plug() {
        mLiveData.observeForever(this);
    }

    void unplug() {
        mLiveData.removeObserver(this);
    }

    @Override
    public void onChanged(@Nullable V v) {
        if (mVersion != mLiveData.getVersion()) {
            mVersion = mLiveData.getVersion();
            mObserver.onChanged(v);
        }
    }
}

通過一個簡單的應用場景可以更加清楚地說明MediatorLiveData的作用。例如,一個Activity界面的UI數據依賴於網絡數據源和數據庫數據,因此會有兩個LiveData。使用MediatorLiveData將兩個LiveData合並后,Activity只需觀察一個MediatorLiveData即可。無論何時,只要任何一個LiveData數據源發生變化,都會通知Activity的UI進行更新。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM