一、LiveData 定義
LiveData 是一種持有可被觀察數據的類。LivaData是有生命周期感知能力的,可以在Activity、Fragment、Services生命周期是活躍狀態時更新組件。
LiveData 實際上就是一個 Data Holder類,既可以持有數據,也可以被監聽,當數據改變時候,可以觸發回調。與Observable不同的是,LiveData綁定了App組件的生命周期,可以在指定在LifeCycle的某個狀態被觸發。
上一文提到 START 和RESUMED 狀態是活躍狀態,才能激活LiveData的使用使其通知數據變化。
所以使用LiveData就需要配合實現前文提到的LifecycleOwner對象。當 對應的生命周期對象DESTROY時候才能移除觀察者Observer 。
ps:這里對生命周期函數的管理尤為重要,因為生命周期結束的時候立刻解除對數據的訂閱,從而避免內存泄露等問題。
二、 LiveData 優點
1、UI和實時數據保持一致,因為LiveData采用餓是觀察者模式,這樣就可以在數據發生改變時候獲得通知更新UI
2、避免內存泄露 ,觀察者被綁定到組件的生命周期上,當被綁定的組件被銷毀時,觀察者會立刻自動清理掉自身的數據
3、不會再產生由於Activity 處於Stop狀態 而引起的崩潰,當Activity處於后台狀態時,是不會收到LiveData的任何event事件的
4、不需要再手動解決生命周期帶來的問題, Livedata可以感知被綁定的組件的生命周期,只有在兩種活躍狀態才會通知數據變化
5、實時數據刷新,當組件處於活躍狀態或者從不活躍狀態到活躍狀態時總是能收到最新的數據
6、解決Configuration Change 屏幕旋轉問題,在屏幕發生旋轉或是被回收再啟動時,立刻能夠獲取到最新的數據
7、數據共享,如果對應的LiveData時單例的話,就能在App的組件間分享數據;這部分詳細的信息可以參考繼承LiveData
三、 LiveData 使用
- 創建一個持有某種數據類型的LiveData (通常在ViewModel中創建)
創建一個LiveData對象
LiveData是一個數據包裝類,具體的包裝對象可以是任何數據,包括集合(List,arrayList)。LiveData通常在ViewModel中創建,然后通過gatter方法獲取。代碼如下:
public class NameViewModelextends ViewModel{
// Create a LiveData with a String
//暫時就把MutableLiveData看成是LiveData吧,下面的文章有詳細的解釋
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<String>();
}
return mCurrentName;
}
// Rest of the ViewModel…
}
- 創建一個定義了onChange()方法的觀察者;這個方法是控制LiveData中數據發生變化時候,采取什么措施(更新界面或是其他)(通常在Activity or Fragment 這樣的UI Controller中創建這個觀察者)
觀察LiveData中的數據
通常情況下都是在組件的onCreate()方法中開始觀察數據,因為:
a、系統會多次調用onResume()方法
b、確保Activity 或是 Fragment在處於活躍狀態時候立刻可以展示需要的數據
public class NameActivity extends AppCompatActivityimplements LifecycleOwner {
private NameViewModelmModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other code to setup or init the activity
...
// Get the ViewModel. 對象
mModel = ViewModelProviders.of(this).get(NameViewModel.class);
// Create the observer which updates the UI. 創建一個觀察者用來更新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.
//通過observe()方法將liveData和 觀察者ViewModel 進行連接
mModel.getCurrentName().observe(this, nameObserver);
}
@Override
publicLifecycleRegistrygetLifecycle() {
returnlifecycleRegistry;
}
}
- 通過observe()方法連接觀察者和LiveData ;observe()需要攜帶一個LifecycleOwner類,這樣就可以讓那個觀察者訂閱LiveData中的數據,在onChange()中實現實時更新。
更新LiveData對象
若想要在 Activity 或是 Fragment 中改變 LiveData的數據值呢?(通過用戶交互事件改變LiveData中的值)。
這時候需要通過Architecture Component提供的MutableLiveData類來完成需求。MutableLiveData是LiveData一個子類。
mButton.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) {
String anotherName = "John Doe”;
mModel.getCurrentName().setValue(anotherName);
}
});
解析:
調用setValue()方法就可以把LiveData中的值改為John Doe。
同樣,通過這種方法修改LiveData中的值同樣會觸發所有對這個數據感興趣的類。
思考:那么setValue()和postValue()有什么不同呢?
答:區別就是setValue()只能在主線程中調用,而postValue()可以在子線程中調用。
再來看如下實例代碼:
publicclass MainActivity extends AppCompatActivity
implements LifecycleRegistryOwner {
privateLifecycleRegistry lifecycleRegistry =newLifecycleRegistry(this);
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// MutableLiveData
UserData userData =newUserData();
userData.observe(this,newObserver() {
@Override
publicvoidonChanged(@Nullable Object o) {
Log.e("UserData","onChanged");
//do Sth to update
}
});
userData.setValue(
"");
}
@Override
publicLifecycleRegistrygetLifecycle() {
returnlifecycleRegistry;
}
}
//UserData 就是ViewModel的 model數據
publicclass UserData
extends LiveData implements LifecycleObserver {
privatestaticfinalString TAG ="UserData”;
publicUserData() {
}
@Override
protectedvoidonActive() {
super.onActive();
Log.e(TAG,"onActive");
}
@Override
protectedvoidonInactive() {
super.onInactive();
Log.e(TAG,"onInactive");
}
@Override
protectedvoidsetValue(Object value) {
super.setValue(value);
Log.e(TAG,"setValue");
}
}
執行效果:
02-2614:43:54.44420885-20885/xxxxxx E/UserData: setValue
02-2614:43:54.45620885-20885/xxxxxx E/UserData: onActive
02-2614:43:54.45620885-20885/xxxxxx E/UserData: onChanged
02-2614:51:11.97420885-20885/xxxxxx E/UserData: onInactive
02-2614:51:23.30420885-20885/xxxxxx E/UserData: onActive
02-2614:51:23.31720885-20885/xxxxxx E/UserData: onInactive
解析:
onActive(): 這個方法在LiveData 在被激活的狀態下執行 ,可以開始執行一些操作
onInActive(): 這個方法在LiveData在失去活性狀態下執行,可以結束執行一些操作
setValue():執行該方法的時候,LiveData 可以觸發它的回調函數
上面 可以看到在Ui Controller層 LiveData是通過 observe,那observe 又做了什么呢?
(一)添加觀察者
分析observe() 源碼可以看到:
/**
* Adds the given observer to the observers list within the lifespan of the given
* owner. The events are dispatched on the main thread. If LiveData already has data
* set, it will be delivered to the observer.
* <p>
*
The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
* or {@link Lifecycle.State#RESUMED} state (active).
* <p>
* If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
* automatically be removed.
* <p>
* When data changes while the {@code owner} is not active, it will not receive any updates.
* If it becomes active again, it will receive the last available data automatically.
* <p>
* LiveData keeps a strong reference to the observer and the owner as long as the
* given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
* the observer & the owner.
* <p>
* If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
ignores the call.
* <p>
* If the given owner, observer tuple is already in the list, the call is ignored.
* If the observer is already in the list with another owner, LiveData throws an
* {@link IllegalArgumentException}.
* * @param owner The LifecycleOwLifecycle.State#STARTEDner which controls the observer
* @param observer The observer that will receive the events
*/
@MainThread
publicvoid
observe(LifecycleOwner owner, Observer<T> observer) {
if(owner.getLifecycle().getCurrentState() == DESTROYED) { //1
// ignore
return;
}
LifecycleBoundObserver wrapper =newLifecycleBoundObserver(owner, observer); //2
LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
if(existing !=null&& existing.owner != wrapper.owner) { //3
thrownewIllegalArgumentException("Cannot add the same observer"
+" with different lifecycles");
}
if(existing !=null) {
return;
}
owner.getLifecycle().addObserver(wrapper); //4
wrapper.activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState())); //5
}
源碼解析:
(1)active()方法的回調是基於 Owner的 [@link Lifecycle.State#STARTED] 或是 [{@link Lifecycle.State#RESUMED} state (active)])
(2) 如果 Owner 狀態轉換至 destroy狀態 ,將會自動移除 observer對象
(3) 如果 Owner 狀態已經處於destroy狀態 ,那么LiveData 則會自動被過濾掉
- 先判斷一下LifecycleRegistry當前的狀態,如果是DESTORYED的話,就直接返回。
- 之后是將LifecycleOwner和創建Observer封裝到LifecycleBoundObserver中。
- 從當前的Oberver集合中查找沒有傳入的Observer對應的包裝類,如果有則返回,沒有則添加。
- LifecycleRegistry添加包裝之后的LifecycleBoundObserver觀察者。
- 更新下當前的包裝類的狀態。
ps:這里需要理解並記住的是LifecycleBoundObserver是一個擁有真正回調Observer和LifecycleOwner的封裝類。
然后這里的addObserver() 方法又進行了什么操作呢?
@Override
public void addObserver(LifecycleObserver observer){
State initialState = mStatet == DESTROY ? DESTROY :INITIALIZED;
ObserverWithState statefulObserver = ObserverWith (observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer , statefulObserver );
if( previous !=null) {
return;
}
boolean isReentrance = mAddingObserverCounter !=0 || mHandlingEvent;
State targetState = calculateTargetState (observer);
mAddingObserverCounter ++ ;
while ( ( statefulObserver.mState.compareTo (targetState) < 0
&& mObserverMap.contains(observer) ) ) {
pushParentState( statefulObserver.mState);
statefulObserver.dispatchEvent(mLifecycleOwner,upEvent(statefulObserver.mState));
popParentState();
targetState = calculateTargetState (observer );
}
if(!isReentrance ){
sync()
}
mAddingObserverCounter - - ;
}
在LifecycleRegistry中添加觀察者,這個LifecycleRegistry是在Activity/Fragment中創建的成員變量。
- 確定初始時LifecycleBoundObserverd的狀態,這里大部分的情況都是INITIALIZED,除非把之前的observe寫在onDestory中,不過估計一般沒人這么寫。
- 將傳入的LifecycleBoundObserver和確定的狀態封裝到一個statefulObserver。在這個過程中會對observer進行一定轉化,將其改變成另一種LifecycleObserver,然后再使用的時候會通過反射去調到實際需要的方法。
- 將封裝過的statefulObserver和傳入的observer添加到當前的一個map中進行保存,如果之前已經添加過的話,就直接返回舊的,沒有的話再放入,返回null。
- 判斷是否可以重入,來決定是否進行同步,這里的parentState暫時先不考慮,等最后的時候再分析。
- 其中while循環的部分是為了修改剛添加進去的ObseverWithState中state的狀態。
- sync方法是事件傳遞的關鍵,在之后也會用到,就先不分析。
(二)生命周期改變
當應用的生命周期變化的時候,會發送對應的生命周期事件到LifecycleRegistry的 handleLifecycleEvent 方法中進行處理 。
/**
* Sets the current state and notifies the observers.
* <p>
* Note that if the {@code currentState} is the same state as the last call to this method,
* calling this method has no effect.
* @param event The event that was received
*/
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
State next = getStateAfter(event);
moveToState(next);
}
private void moveToState(State next) {
if (mState == next) {
return;
}
mState= next;
if (mHandlingEvent || mAddingObserverCounter != 0) {
mNewEventOccurred = true;
// we will figure out what to do on upper level.
return;
}
mHandlingEvent = true;
sync();
mHandlingEvent = false;
}
首先設置當前的LifecycleRegistry 中的 mState值,之后執行synv方法
// happens only on the top of stack (never in reentrance),
// so it doesn't have to take in account parents
private void sync() {
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
Log.w(LOG_TAG, "LifecycleOwner is garbage collected, you shouldn't try dispatch "
+ "new events from it.");
return;
}
while (!isSynced()) { //進行同步
mNewEventOccurred = false;
// no need to check eldest for nullability, because isSynced does it for us.
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
backwardPass(lifecycleOwner); //逆推計算
}
Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
forwardPass(lifecycleOwner); //正推計算
}
}
mNewEventOccurred = false;
}
解析: 該方法先判斷是否可以進行同步操作,判斷條件是當前map中的oberver數量和狀態,之后會根據當前的mObserverMap中保存的Observer的狀態和當前的Registry的狀態進行對比,來決定是進行正推計算還是反推計算。
正推計算:
private void forwardPass(LifecycleOwner lifecycleOwner) {
Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
mObserverMap.iteratorWithAdditions();
while (ascendingIterator.hasNext() && !mNewEventOccurred) {
Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
ObserverWithState observer= entry.getValue();
while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
&& mObserverMap.contains(entry.getKey()))) {
pushParentState(observer.mState);
observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
popParentState();
}
}
}
解析:把當前的observerMap中的數據進行迭代 ,判斷狀態之后執行 observer.dispatchEvent() 方法進行同步Observer 操作
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
在這里先設置當前Observer的狀態通過getStateAfter(),之后調用Observer的onStateChanged方法,這個方法最終會通過反射原理,最終調到LiveData中的 LifecycleBoundObserver的 onStateChange()方法
(三)數據更新
onChange()調用鏈 基本如:
setValue(T value ) —> dispatchingValue(@Nullable LifecycleBoundObserver initiator ) —> considerNotify(LifecycleBoundObserver observer —> onChange)
首先看一眼這個setValue()方法
/**
* Sets the value. If there are active observers, the value will be dispatched to them.
* <p>
* This method must be called from the main thread. If you need set a value from a background
* thread, you can use {@link #postValue(Object)}
*
* @param value The new value
*/
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
將成員變量mData賦值,之后調用了dispatchingValue()方法
在這個dispatchingValue方法里面又干了什么呢?
private void
dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator); //importing
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;
}
這里關鍵方法considerNotify ,如果是通過setValue方法進行更新的話,會更新所有的observer;
注意,如果是通過前面的handleLifecycleEvent方法進行更新的話,那么只會更改當前的observer。
下面再看下 onChange()方法 的源碼:
privatevoid
considerNotify(LifecycleBoundObserver observer) {
if(!
observer.active) {
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(!isActiveState(observer.owner.getLifecycle().getCurrentState())) {
observer.activeStateChanged(false);
return;
}
if(observer.lastVersion >= mVersion) {
return;
}
observer.lastVersion = mVersion;
//noinspection unchecked
observer.observer.onChanged((T) mData);
}
- 首先檢查當前的observer的active 之后會檢查observer的owner的狀態是否可用
- 其次判斷當前版本,最后更新數據
上面已經知道LiveData的活躍狀態是 STARTED 和 RESUMED 。
那么如何在“活躍狀態下傳遞數據呢”?
下面是實例代碼:
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);
}
}
如果把StockLiveData寫成單例模式,那么還可以在不同的組件間共享數據。代碼如下:
public class StockLiveData extends LiveData<BigDecimal> {
private static StockLiveData sInstance;
private StockManager mStockManager;
private SimplePriceListener mListener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
setValue(price);
}
};
@MainThread
public static StockLiveData get(String symbol) {
if (sInstance == null) {
sInstance = new StockLiveData(symbol);
}
return sInstance;
}
private StockLiveData(String symbol) {
mStockManager = new StockManager(symbol);
}
@Override
protected void onActive() {
mStockManager.requestPriceUpdates(mListener);
}
@Override
protected void onInactive() {
mStockManager.removeUpdates(mListener);
}
}
四、LiveData 的 Transformations
一般情況下再使用LiveData的時候都是它的子類MutableLiveData。有時候需要對一個LiveData做observer,但是這個LiveData又和另一個LiveData有依賴關系,類似於RxJava中的操作符。這時候需要這樣進行:在LiveData的數據被分發到各個組件之前轉換的值,但是LiveData里面的數據本身的值並沒有改變。
- Transformations.map()
用於事件流的傳遞,用於觸發下游數據
LiveData <User> userLiveData = … ;
LiveData<String> userName = Transformations.map (userLiveData ,user -> {
user.name + “” + user.lastName });
把原來是包含User的 LiseData轉換 成包含 String 的LiveData傳遞出去
- Transformations.switchMap()
用於事件流的傳遞,用於觸發上游數據
private LiveData<User> getUser(String id){…}
LiveData<String> userId = … ;
LiveData<User> user = Transformations.switchMap (userId ,id -> getUser(id) );
switchMap()區別於map() 的是,傳遞給switchMap()的函數必須返回LiveData對象。類似於LiveData ,Transformations也可以在觀察者的整個生命中存在。只有在觀察者處於觀察LiveData狀態時,Transformations才會運算,其是延遲運算 lazily calculated ,而生命周期感知能力確保不會因為延遲發生任何問題。
Transformations的使用場景
假設在ViewModel對象內部需要一個 Lifecycle對象,此時推薦使用Transformations。比如
有個Ui組件接收用戶輸入的地址,返回對應的郵編。 那么 代碼如下:
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository ;
public MyViewModel( PostalCodeRepository repository ){
this.repository= repository;
}
private LiveData <String> getPostalCode (String address ){
//Don’t do this
return repository.getPostCode( address );
}
}
看代碼中的注釋,有個// DON'T DO THIS (不要這么干),這是為什么?有一種情況是如果UI組件被回收后又被重新創建,那么又會觸發一次 repository.getPostCode(address)查詢,而不是重用上次已經獲取到的查詢。那么應該怎樣避免這個問題呢?看一下下面的代碼:
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
private final MutableLiveData<String> addressInput = new MutableLiveData();
public final LiveData<String> postalCode =
Transformations.switchMap(addressInput, (address) -> {
return repository.getPostCode(address); //在輸入變化時才會調用
});
public MyViewModel(PostalCodeRepository repository) {
this.repository = repository
}
private void setInput(String address) {
addressInput.setValue(address);
}
}
解析:
postalCode這個變量存在的作用是把輸入的addressInput轉換成郵編,那么只有在輸入變化時才會調用repository.getPostCode()方法。這就好比你用final來修飾一個數組,雖然這個變量不能再指向其他數組,但是數組里面的內容是可以被修改的。繞來繞去就一點:當輸入是相同的情況下,用了 switchMap() 可以減少沒有必要的請求。並且同樣,只有在觀察者處於活躍狀態時才會運算並將結果通知觀察者。
延伸擴展 合並多個LiveData中的數據
MediatorLiveDate
其是LiveData 的子類 ,可以通過MediatorLiveDate合並都個LiveData數據源。同樣任意一個來源的LiveData數據發生變化,MediatorLiveDate 都會通知觀察它的對象。
五、小結
- LiveData的優點
- LiveData的使用
- LiveData 和 Owner的聯結器 observe方法
- LiveData的三個重要方法
- onActive的作用
- 當生命周期處於onStart,onResume是被激活 ,且當這個方法被調用時,表示LiveData的觀察者開始使用了,也就是說應該注冊事件監聽了
- onInActive的作用
- 當生命周期處於onDestroy時激活,且當這個方法被調用時,表示LiveData的觀察者停止使用了,此時應該將監聽器移除
- setValue的作用
- 當調用此方法時,會激活Observer內的onChange方法,且通過調用這個方法來更新LiveData的數據,並通知處於活動狀態的觀察者
- LiveData的轉換
系列文章列表: