上一篇文章ViewModel簡單使用與解析我們說了ViewModel相關(guān)的知識(shí)漱竖,接下來我們要說的是ViewModel的終極搭檔LiveData岖是。
先來說一下LiveData的優(yōu)點(diǎn):
-
減少內(nèi)存泄漏畔师,不需要手動(dòng)處理生命周期掏颊,
LiveData會(huì)綁定實(shí)現(xiàn)了LifecycleOwner接口的對(duì)象送膳,并會(huì)在這些對(duì)象被銷毀后自行清理普碎。
Activity/Fragment都繼承并實(shí)現(xiàn)了這個(gè)接口吼肥,所以我們只需對(duì)數(shù)據(jù)進(jìn)行訂閱便可,不需要手動(dòng) 去停止或恢復(fù)觀察麻车。(也可以使用observeForever(Observer)方法注冊(cè)一個(gè)沒有關(guān)聯(lián)LifecycleOwner的對(duì)象缀皱,但是這得手動(dòng)調(diào)用removeObserver(Observer)方法進(jìn)行移除) -
在最合適的時(shí)候通知更新數(shù)據(jù)
LiveData只會(huì)將數(shù)據(jù)通知給處于活躍狀態(tài)下的對(duì)象,因此可以規(guī)避很多異步任務(wù)結(jié)束后更新已經(jīng)被回收的UI而造成的空指針異常动猬,而非活躍狀態(tài)下的對(duì)象當(dāng)基狀態(tài)變成活躍時(shí)也會(huì)收到最新的數(shù)據(jù)啤斗。 -
正確應(yīng)對(duì)Configuration Change
如果一個(gè)Activity或Fragment由于Configuration Change更改(如設(shè)備旋轉(zhuǎn))而重新創(chuàng)建,它會(huì)立即收到最新的可用數(shù)據(jù)赁咙。 -
共享資源
您可以使用單例模式擴(kuò)展LiveData對(duì)象并包裝成系統(tǒng)服務(wù)钮莲,以便在應(yīng)用程序中進(jìn)行共享。LiveData對(duì)象一旦連接到系統(tǒng)服務(wù)彼水,任何需要該資源的Observer都只需觀察這個(gè)LiveData對(duì)象崔拥。 有關(guān)更多信息,請(qǐng)參閱擴(kuò)展LiveData凤覆。
1.創(chuàng)建LiveData對(duì)象
public class MViewModel extends ViewModel {
MutableLiveData<String> mString;
public MutableLiveData<String> getString(){
if(mString==null){
mString=new MutableLiveData<>();
}
return mString;
}
public MutableLiveData<String> getMsgString(){
if(msgString==null){
msgString=new MutableLiveData<>();
}
return msgString;
}
}
一般都是在ViewModel中聲明和保存LiveData,這有利于:
- 保持Activity/Fragment的精簡性握童,這些UI控制器負(fù)責(zé)顯示數(shù)據(jù)而不是保存數(shù)據(jù)狀態(tài)。
- 將LiveData實(shí)例與特定Activity/Fragment實(shí)例分離叛赚,這將使得LiveData對(duì)象在發(fā)生Configuration Change后仍然存活澡绩。
2.訂閱LiveData對(duì)象
官方推薦在應(yīng)用程序組件的onCreate()方法開始觀察LiveData對(duì)象稽揭,理由是:
- 確保系統(tǒng)不會(huì)從Activity或Fragment的onResume()方法中進(jìn)行多余的調(diào)用。
- 確保Activity或Fragment一旦變?yōu)榛顒?dòng)狀態(tài)時(shí)肥卡,就有可展示的數(shù)據(jù)溪掀。 當(dāng)應(yīng)用程序組件處于STARTED狀態(tài),它就需從它所觀察的LiveData對(duì)象中接收到最新的值步鉴。 所以我們需要在一開始就設(shè)置好訂閱揪胃。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView=findViewById(R.id.desc);
mViewModel = ViewModelProviders.of(this).get(MViewModel.class);
mViewModel.getString().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.e("MainActivity", "耗時(shí)任務(wù)結(jié)束返回?cái)?shù)據(jù)");
mTextView.setText(s);
}
});
3.更新LiveData對(duì)象
一般在ViewModel中對(duì)數(shù)據(jù)進(jìn)行處理,當(dāng)我們拿到數(shù)據(jù)后將值賦值給LiveData
public void startTask(){
new Thread(){
@Override
public void run() {
//請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)氛琢、數(shù)據(jù)庫喊递、加載大圖等。
//如果在Activity轉(zhuǎn)屏的時(shí)候取消這些任務(wù)阳似,那恢復(fù)的時(shí)候就要重新加載骚勘,勢必浪費(fèi)資源
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//更新LiveData
mString.postValue("我是來自3秒后的數(shù)據(jù)");
super.run();
}
}.start();
}
setValue()或者postValue()都可以用來更新LiveData的值,區(qū)別在于:
setValue要在主線程中使用撮奏,postValue在后臺(tái)線程中使用俏讹。
4.LiveData Transformations
有時(shí)候我們想在ViewModel中對(duì)LiveData進(jìn)行數(shù)據(jù)轉(zhuǎn)換之后再輸出給observer,比如我我拿到了用戶ID,我們需要通過ID拿到用戶信息再去更新UI畜吊,那我們就可以用Transformations來對(duì)一個(gè)LiveData對(duì)象進(jìn)行轉(zhuǎn)換泽疆,Transformations類目前只提供兩個(gè)轉(zhuǎn)換方法map()和switchMap():
static <X, Y> LiveData<Y> map(LiveData<X> source,Function<X, Y> mapFunction) {}
static <X, Y> LiveData<Y> switchMap(LiveData<X> source,Function<X, LiveData<Y>> switchMapFunction){}
簡單對(duì)比一下你會(huì)發(fā)現(xiàn)這兩個(gè)方法只是最后一個(gè)傳入的參數(shù)不同而已,返回結(jié)果跟第一個(gè)參數(shù)是一樣的玲献,至于選擇哪個(gè)方法殉疼,就完全是看你要傳入的參數(shù)類型了
LiveData<Long> userId...;
LiveData<UserBean> userBean=Transformations.map(userId, new Function<Long, UserBean>() {
@Override
public UserBean apply(Long input) {
//比如說你剛好有個(gè)方法是通過userId獲取到userBean,并且是返回UserBean類型的就用map
return new UserBean();
}
});
LiveData<UserBean> userBean=Transformations.switchMap(userId, new Function<Long, LiveData<UserBean>>() {
@Override
public LiveData<UserBean> apply(Long input) {
//比如說你剛好有個(gè)方法是通過userId獲取到userBean捌年,并且是返回LiveData<UserBean>類型的就用switchMap
return new MutableLiveData<UserBean>(){};
}
});
再來看下該類完整的代碼
public class Transformations {
private Transformations() {
}
@MainThread
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
@MainThread
public static <X, Y> LiveData<Y> switchMap(
@NonNull LiveData<X> source,
@NonNull final Function<X, LiveData<Y>> switchMapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
LiveData<Y> newLiveData = switchMapFunction.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;
}
}
你會(huì)發(fā)現(xiàn)其實(shí)就是通過類把LiveData<X>轉(zhuǎn)換成了MediatorLiveData<Y>輸出瓢娜。
5. MediatorLiveData
我們前面有提到過,只有LifecycleOwner對(duì)象才能使用observer方法對(duì)LiveData進(jìn)行監(jiān)聽延窜,而Transformations的轉(zhuǎn)換思路顯然是通過對(duì)上一個(gè)LiveData進(jìn)行了監(jiān)聽然后在其值發(fā)生變化的時(shí)候封裝成MediatorLiveData對(duì)象輸出。所以應(yīng)該是用到了LiveData的observeForever方法抹锄。
我們先來看下它的addSource方法
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
傳入的LiveData和Observer被用來構(gòu)造Source對(duì)象逆瑞,看下Source代碼
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
final Observer<? super V> mObserver;
int mVersion = START_VERSION;
Source(LiveData<V> liveData, final Observer<? super V> observer) {
mLiveData = liveData;
mObserver = observer;
}
void plug() {
//此處完成了對(duì)傳入的LiveData的訂閱
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);
}
}
}
果然是用到了observeForever對(duì)傳入的LiveData進(jìn)行了監(jiān)聽,然后在onChanged方法將值繼續(xù)傳遞下去伙单。而MediatorLiveData可以多少調(diào)用addSource获高,其內(nèi)部用了一個(gè)Map來存儲(chǔ)構(gòu)造生成的Source對(duì)象。
MediatorLiveData相當(dāng)于一個(gè)自定義的LiveData,其內(nèi)部定義了一個(gè)Map用于存儲(chǔ)
private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
所以MediatorLiveData除了用于上面Transformations的轉(zhuǎn)換操作之外還可用來做合并訂閱的操作吻育。
* LiveData<Integer> liveData1 = ...;
* LiveData<Integer> liveData2 = ...;
*
* MediatorLiveData<Integer> liveDataMerger = new MediatorLiveData<>();
* liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
* liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
這樣只要是liveData1念秧、liveData2其中一個(gè)數(shù)據(jù)的變化都會(huì)引發(fā)liveDataMerger去發(fā)出更新數(shù)據(jù)的通知。