Android Architecture Components 系列(三) LiveData

    1、LiveData 定義
    LiveData 是一種持有可被觀察數據的類。LivaData是有生命週期感知能力的,能夠在Activity、Fragment、Services生命週期是活躍狀態時更新組件。
   LiveData 實際上就是一個 Data Holder類,既能夠持有數據,也能夠被監聽,當數據改變時候,能夠觸發回調。與Observable不一樣的是,LiveData綁定了App組件的生命週期,能夠在指定在LifeCycle的某個狀態被觸發。
    上一文提到 START 和RESUMED 狀態是活躍狀態,才能激活LiveData的使用使其通知數據變化。
因此使用LiveData就須要配合實現前文提到的LifecycleOwner對象。當 對應的生命週期對象DESTROY時候才能移除觀察者Observer 。
 
ps:這裏對生命週期函數的管理尤其重要,由於生命週期結束的時候馬上解除對數據的訂閱,從而避免內存泄露等問題。
 
   2、 LiveData 優勢 
    一、UI和實時數據保持一致,由於LiveData採用餓是觀察者模式,這樣就能夠在數據發生改變時候得到通知更新UI
    二、避免內存泄露 ,觀察者被綁定到組件的生命週期上,當被綁定的組件被銷燬時,觀察者會馬上自動清理掉自身的數據
    三、不會再產生因爲Activity 處於Stop狀態 而引發的崩潰,當Activity處於後臺狀態時,是不會收到LiveData的任何event事件的
    四、不須要再手動解決生命週期帶來的問題, Livedata能夠感知被綁定的組件的生命週期,只有在兩種活躍狀態纔會通知數據變化
    五、實時數據刷新,當組件處於活躍狀態或者從不活躍狀態到活躍狀態時老是能收到最新的數據
    六、解決Configuration Change 屏幕旋轉問題,在屏幕發生旋轉或是被回收再啓動時,馬上可以獲取到最新的數據
    七、數據共享,若是對應的LiveData時單例的話,就能在App的組件間分享數據;這部分詳細的信息能夠參考繼承LiveData
        
   3、 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 &amp; 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 則會自動被過濾掉
 
  1. 先判斷一下LifecycleRegistry當前的狀態,若是是DESTORYED的話,就直接返回。
  2. 以後是將LifecycleOwner和建立Observer封裝到LifecycleBoundObserver中。
  3. 從當前的Oberver集合中查找沒有傳入的Observer對應的包裝類,若是有則返回,沒有則添加。
  4. LifecycleRegistry添加包裝以後的LifecycleBoundObserver觀察者。
  5. 更新下當前的包裝類的狀態。
        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);
         } 
    }
    4、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 都會通知觀察它的對象。
 
 
    5、小結
  •  LiveData的優勢
  •  LiveData的使用
  •  LiveData 和 Owner的聯結器 observe方法
  •  LiveData的三個重要方法
    • onActive的做用 
      • 當生命週期處於onStart,onResume是被激活 ,且當這個方法被調用時,表示LiveData的觀察者開始使用了,也就是說應該註冊事件監聽了
    • onInActive的做用
      • 當生命週期處於onDestroy時激活,且當這個方法被調用時,表示LiveData的觀察者中止使用了,此時應該將監聽器移除
    • setValue的做用
      • 當調用此方法時,會激活Observer內的onChange方法,且經過調用這個方法來更新LiveData的數據,並通知處於活動狀態的觀察者
  • LiveData的轉換

 

系列文章列表:
相關文章
相關標籤/搜索