天天看點

Android Architecture Components(二)LiveData分析

LiveData簡介

文章分為兩部分,第一部分是對官網介紹的翻譯加自己的一些了解,第二部分是源碼解析。我們先來看一下官方網站給出的定義:

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

LiveData是可觀察的資料容器裡。不同于普通的被觀察者,LiveData是可預見生命周期的,意味着它不會對其他App元件的生命周期造成影響,例如activities、fragments或者services。這種對生命周期的可見性保證了LiveData隻會在目前App元件(觀察者)處于active生命周期狀态時(STARTED和RESUMED)進行通知。

LiveData considers an observer, which is represented by the Observer class, to be in an active state if its lifecycle is in the STARTED or RESUMED state. LiveData only notifies active observers about updates. Inactive observers registered to watch LiveData objects aren’t notified about changes.

LiveData認為當觀察者處于STARTED或RESUMED狀态時,是處于active狀态。LiveData隻會在觀察者處于active狀态時通知updates。inactive狀态下的觀察者盡管注冊了也不會得到改動通知。

You can register an observer paired with an object that implements the LifecycleOwner interface. This relationship allows the observer to be removed when the state of the corresponding Lifecycle object changes to DESTROYED. This is especially useful for activities and fragments because they can safely observe LiveData objects and not worry about leaks—activities and fragments are instantly unsubscribed when their lifecycles are destroyed.

你可以注冊一個 與實作了LifecycleOwner接口的對象配對的 觀察者。這種關系可以保證當對應的Lifecycle對象進入DESTROYED狀态時,可以移除觀察者。這對于activities和fragments尤其實用,因為這樣它們可以安全地觀察LiveData對象,而不用擔心記憶體洩漏-activities和fragments在被destroy時會立即取消訂閱。

LiveData的優勢

確定你的UI顯示與資料一緻

LiveData遵循了觀察者模式,當生命周期狀态變化時,LiveData會通知觀察者。你可以将更新觀察者UI的代碼統一起來。觀察者可以在任何時間任意改變時更新UI,而不僅時在app資料改變時才更新UI。

無記憶體洩露

觀察者綁定在Lifecycle上,并在相關聯的Lifecycle對象被銷毀時自己clean up。

不會因為activities處于stopped狀态而崩潰

如果觀察者的生命周期處于inactive狀态,例如activity處于背景棧中,但是它無法接收到任何LiveData事件。

無需手動處理生命周期

UI元件隻觀察對應資料,而不會停止/恢複觀察。LiveData在觀察過程中會自動地管理這些,因為它可以感覺到對應的生命周期狀态。

始終保持最新資料

如果生命周期進入inactive狀态,在重新變為active狀态時,會立刻擷取到最後發送的資訊。

正确處理配置更改

如果一個activity或fragment因為配置更改而recreate,例如裝置旋轉,它會立刻接收到最新的有效資料。

共享資源

可以使用單例模式來擴充LiveData,用來包裝系統服務,進而在App中可以共享使用。LiveData連接配接系統服務一次,之後任意需要該資源的觀察者都可以通過觀察LiveData來擷取資源。

使用LiveData元件

1.建立LiveData執行個體來儲存某一種類資料,這通常在ViewModel類中進行。

2.建立一個定義了onChanged()方法的觀察者對象,用來控制當LiveData資料發生改變時如何進行處理。通常在UI controller中建立這個對象,例如在activity或fragment中。

3.通過observe()方法将觀察者和LiveData對象連接配接起來。這個observe()方法需要一個LifecycleOwner對象,這将觀察者訂閱到了LiveData對象上,以保證可以接收到更改通知。通常在UI controller中連接配接對象,例如在activity或fragment中。

Note:使用observeForever(observer)方法注冊觀察者可以不需要和LifecycleOwner

對象關聯。這種情況下,觀察者被預設為永遠處于active狀态而且永遠可以接收修改。可以通過removeObserver(observer)方法來移除這些觀察者。

當你修改LiveData中儲存的資料時,所有處于active狀态的觀察者都會被觸發。

LiveData允許UI controller觀察者訂閱更新。當LiveData中的資料改變時,UI會立即自動更新。

建立LiveData

LiveData可以用來包裝任意資料,包括集合對象。LiveData對象通常存儲在ViewModel中,通過一個getXxx方法來通路。

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...
}
           
觀察LiveData

大多數情況下,應該在App元件的onCreate()方法中觀察LiveData,理由如下:

1.確定不會發出多餘的請求,例如在activity或fragment的onResume()方法中。

2.確定了當activity或fragment變為active狀态時有可以展示的資料。當App元件進入STARTED狀态時,它會從觀察的LiveData對象接收到最新的資料(當被觀察的LiveData對象被設定了新資料的情況下)。

通常情況下,LiveData隻在資料發生改變時進行傳遞,且隻傳遞給處于active狀态下的觀察者。一個例外的情況是:當觀察者從inactive狀态切換為active狀态時,也會收到一次更新,但如果非初次從inactive切換到active狀态,且資料未發生過變化,則不會接收到更新通知。

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.
        // observe()調用後,将nameObserver作為一個參數傳了進去,會将mCurrentName中最近存儲的資料通過調用onChanged立即傳過去。如果LiveData未設定數值,則不會調用。
        mModel.getCurrentName().observe(this, nameObserver);
    }
}
           
更新LiveData

LiveDate未提供public方法進行資料更新操作,需要通過MutableLiveData類提供的setValue(T)和postValue(T),且必須通過這倆個方法對LiveData中儲存的資料進行修改。

MutableLiveData代碼如下:

package android.arch.lifecycle;

/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
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);
    }
}
           

通常MutableLiveData隻在ViewModel中使用,ViewModel隻将其暴露給觀察者。

示例:

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

Note:在UI線程中使用setValue(),工作線程中使用postValue()。

擴充LiveData

繼承LiveData,實作單例模式,重寫onActive和onInactive函數。

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,實作資料共享;

onActive():目前LiveData擁有處于active狀态的觀察者時調用,開始對資料進行觀察;

onInactive():目前LiveData沒有處于active狀态的觀察者時調用,用于無監聽時的一些處理。

LiveData中資料轉換

通過Transformations.map()和.switchMap()進行轉換

LiveData<User> userLiveData = ...;
    LiveData<String> userName = Transformations.map(userLiveData,        user -> {
        user.name + " " + user.lastName
    });

    // map方法的源碼:
    @MainThread
    public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
            @NonNull final Function<X, Y> func) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(func.apply(x));
            }
        });
        return result;
    }
    
    // swichMap方法的源碼:
    @MainThread
    public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
            @NonNull final Function<X, LiveData<Y>> func) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(trigger, new Observer<X>() {
            LiveData<Y> mSource;

            @Override
            public void onChanged(@Nullable X x) {
                LiveData<Y> newLiveData = func.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                if (mSource != null) {
                    result.addSource(mSource, new Observer<Y>() {
                        @Override
                        public void onChanged(@Nullable Y y) {
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }
    
    //兩者的差別在于,switchMap在onChanged中觸發了一個新的改動時,會将轉換後的LiveData加入觀察者模式,移除前一個;
    //而map則是将資料的改動放入同一個LiveData
           

上面代碼中兩個方法的實作都使用了MediatorLiveData類,該類的作用是将多個資料源通過addSource方法加入到SafeIterableMap<LiveData<?>, Source<?>>中,并統一管理onActive和onInactive時的訂閱。該類也可用于将多個源合并在一起,由觀察者去訂閱,例如:我們有兩個LiveData執行個體1和2,我們想将1和2合并為一個liveDataMerger,無論哪一個發生改變,都将通知觀察者。這時,1和2就是merger中的source。

源碼分析

1.修改資料

在開發中使用的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的postValue和setValue方法(原方法為protected)。

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

setValue是需要在主線程進行調用,而postValue用于工作線程中調用。

首先先看postValue方法,注釋中寫同時調用liveData.postValue(“a”)和liveData.setValue(“b”);的話,b會在a之前被傳回。這也是官方建議在主線程要使用setValue的原因。

在postValue中,通過synchronized關鍵字來保證同步。代碼中postTask的值是目前儲存的mPendingData是否為NOT_SET,而mPendingData被設定為NOT_SET實在最後一行,執行的mPostValueRunnable中:

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

是以當多個postValue同時調用時,如果前面送出的未來的及處理,那麼後面的送出會将前面覆寫,并在(!postTask)處傳回,而runnable中最後調用的仍是setValue方法。

下面我們來看setValue方法:

@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        // 分發資料
        dispatchingValue(null);
    }
    
    private void dispatchingValue(@Nullable LifecycleBoundObserver initiator) {
        // mDispatchingValue是用來防止在更新觀察者消息時,接到新的更新消息,造成同步問題:
        // 開始時判斷是否為true,為true則傳回;執行過程中為true,執行完為false。
        // 而在周遊時,通過mDispatchInvalidated來判斷過程中是否有新的更新rugosa有,則停止目前的分發
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                // 目前狀态變化時調用,資料如果未修改,在considerNotify中不會update observer
                considerNotify(initiator);
                initiator = null;
            } else {
                // setValue中傳入的為null,即周遊訂閱的觀察者,調用對應onChanged方法
                for (Iterator<Map.Entry<Observer<T>, LifecycleBoundObserver>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    
    private void considerNotify(LifecycleBoundObserver observer) {
        if (!observer.active) {
            return;
        }
        // 目前處于inactive狀态時,計算是否回調onInactive
        if (!isActiveState(observer.owner.getLifecycle().getCurrentState())) {
            observer.activeStateChanged(false);
            return;
        }
        // 資料未變化,傳回
        if (observer.lastVersion >= mVersion) {
            return;
        }
        observer.lastVersion = mVersion;
        // 調用onChanged,通知資料改變
        observer.observer.onChanged((T) mData);
    }
           
2.添加觀察者

上文中提到過,LiveData通過observe函數進行觀察者的訂閱:

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        // 判斷狀态
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        
        // 将目前LifecycleOwner(activity or fragment)與observer封裝成一個LifecycleBoundObserver對象,并判斷目前觀察者是否已經注冊過
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing.owner != wrapper.owner) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        
        // 注冊Lifecycle,狀态改變時會回調onStateChanged函數,對LiveData的狀态進行同步修改
        owner.getLifecycle().addObserver(wrapper);
    }
           

在訂閱中綁定了Lifecycle,實作了LiveData的生命周期訂閱,用于更新狀态。而之前說過的observeForever方法也是調用了observe方法,第一個參數為ALWAYS_ON,以此達到預設為active狀态的效果:

private static final LifecycleOwner ALWAYS_ON = new LifecycleOwner() {

        private LifecycleRegistry mRegistry = init();

        private LifecycleRegistry init() {
            LifecycleRegistry registry = new LifecycleRegistry(this);
            registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
            registry.handleLifecycleEvent(Lifecycle.Event.ON_START);
            registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
            return registry;
        }

        @Override
        public Lifecycle getLifecycle() {
            return mRegistry;
        }
    };