LiveData 是一個可以感知 Activity 、Fragment生命周期的數據容器。 當 LiveData 所持有的數據改變時,它會通知相應的界面代碼進行更新。同時,LiveData 持有界面代碼 Lifecycle 的引用,這意味著它會在界面代碼(LifecycleOwner)的生命周期處于 started 或 resumed 時作出相應更新,而在 LifecycleOwner 被銷毀時停止更新。
所以LiveData有三個優(yōu)點
- 不用手動控制生命周期
- 不用擔心內存泄漏
- 天然的觀察者模式,觀察數據變化
- LiveData在處于inactive狀態(tài)時,不會數據更新的通知,回到active狀態(tài)時,會刷新最新的變化數據。
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在純數據情況下替代單例
通過這樣簡單的封裝,LiveData可以完成跨Activity的數據共享。注意,ViewModel并不能跨Activity共享數據,VM必須依賴于單個Activity的創(chuàng)建和銷毀。
public class SingleLiveData extends MutableLiveData<T> {
private static SingleLiveData sInstance;
private SingleLiveData() {
}
@MainThread
public static SingleLiveData getInstance() {
if (sInstance == null) {
sInstance = new SingleLiveData();
}
return sInstance;
}
@Override
public void setValue(T value) {
super.setValue(value);
}
@Override
public void postValue(T value) {
super.postValue(value);
}
}
- LiveData感知生命周期變化
在聲明周期變化、移除觀察者、數據變化、observeForever情況下都會調到這個方法,最終調用considerNotify通知觀察者數據發(fā)生改變。
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);
}
}
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);
}
- Transformations
4.1 Map轉換:
本質上是一種針對LiveData返回的數據的適配器作用。如LiveData返回Integer類型,而數據接收處要使用String類型,可以使用map進行如下轉換
mNumberLiveData = new MutableLiveData<Integer>();
Transformations.map(mNumberLiveData, new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
return "" + integer;
}
}).observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
Log.d(TAG, "onChanged: " + s);
}
});
addSource的時候Observer會觀察source的變化,source數據變化回調到Observer的onChanged,隨機引起map返回的LiveData即result調用setValue通知result的觀察者數據發(fā)生變化
@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;
}
4.2 switchMap轉換
將初始的LiveData經過switchMap后轉換成另一種形式的數據,并返回一個LiveData
比如,我們一方面需要一個存儲 userId 的 LiveData,另一方面又需要維護一個存儲 User 信息的 LiveData,而后者的 User 則是根據 userId 來從數據庫中查找的,二者需要對應。這時候我們就可以使用Transformations類的switchMap(...)操作符。
MutableLiveData<String> userIdLiveData = new MutableLiveData<>();
LiveData<User> userLiveData = Transformations.switchMap(userIdLiveData, new Function<String, LiveData<User>>() {
@Override
public LiveData<User> apply(String userId) {
// 根據 userId 返回一個 LiveData<User>,可以通過Room來獲取
return getUser(userId);
}
});
@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;
}