一、前言
LiveData 可觀察數(shù)據(jù)存儲(chǔ)類屬于谷歌在2018推出Android jetpack(外網(wǎng))其中的軟件架構(gòu)組件中的一個(gè)。在谷歌開發(fā)者網(wǎng)站有詳細(xì)介紹LiveData(外網(wǎng))。本文以總結(jié)為目的,采用更加清晰和有條理的方式解讀LiveData。
閱讀前準(zhǔn)備
便于理解,如果你已經(jīng)知道什么是Lifecycle、觀察者模式和ViewModel 更好,那么理解此篇文章便輕車熟路。
避免過多而雜的介紹,部分知識(shí)不詳述,請(qǐng)閱讀筆者鏈接文章或者Google。
全文就一個(gè)核心
LiveData是結(jié)合Lifecycle和觀察者模式的數(shù)據(jù)存儲(chǔ)類
二、LiveData
谷歌爸爸的介紹
LiveData是一種可觀察的數(shù)據(jù)存儲(chǔ)器類。與常規(guī)的可觀察類不同,LiveData 具有生命周期感知能力,意指它遵循其他應(yīng)用組件(如 Activity、Fragment 或 Service)的生命周期。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者。
簡(jiǎn)單理解
LiveData就是結(jié)合生命周期+觀察者模式的數(shù)據(jù)存儲(chǔ)類。方便我們根據(jù)生命周期來監(jiān)聽數(shù)據(jù)變化的。由于這個(gè)結(jié)構(gòu)的特性,所以它擁有以下特點(diǎn)
1、確保界面符合數(shù)據(jù)狀態(tài);2、不會(huì)發(fā)生內(nèi)存泄露;3、不會(huì)因 Activity 停止而導(dǎo)致崩潰;4、不再需要手動(dòng)處理生命周期;5、數(shù)據(jù)始終保持最新狀態(tài);6、適當(dāng)?shù)呐渲酶模?、共享資源
導(dǎo)入
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
三、詳細(xì)介紹
LiveData介紹就如下幾個(gè)點(diǎn)
- LiveData基本使用
- LiveData自定義LiveData
- LiveDa數(shù)據(jù)轉(zhuǎn)換
- LiveData合并多個(gè)數(shù)據(jù)
3.1、基本使用
這里說下為啥別的文章或者官網(wǎng)都是結(jié)合ViewModel來講的例子,ViewModel就是存儲(chǔ)和管理界面數(shù)據(jù)的一個(gè)類。我們LiveData就是一種數(shù)據(jù)。如果不和ViewModel一起講,不影響我們理解LiveData的核心思想。但是并不推薦直接在Activity或者Fragment里直接寫LiveData變量來存儲(chǔ)數(shù)據(jù)。這會(huì)讓他們過于臃腫,所以還是用推薦存儲(chǔ)數(shù)據(jù)的方式ViewModel。
如果你還不了解ViewModel你可以簡(jiǎn)單理解為它就是存儲(chǔ)數(shù)據(jù)的一個(gè)地方。
LiveData在使用上除了和ViewModel結(jié)合以外無非觀察者模式三個(gè)步驟
- 創(chuàng)建LiveData,即創(chuàng)建被觀察者
- 添加Observe,添加觀察者
- 數(shù)據(jù)改變是修改UI,觀察者監(jiān)聽
public class MyViewModel extends ViewModel {
MutableLiveData<String> name;
public MutableLiveData<String> getName() {
if (name == null) {
name = new MutableLiveData<>();
}
return name;
}
}
ViewModelProvider.Factory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication());
ViewModelProvider viewModelProvider = new ViewModelProvider(this, factory);
viewModel = viewModelProvider.get(MyViewModel.class);
viewModel.getName().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
textView.setText(s);
}
});
viewModel.getName().setValue("yink");
1、MyViewModel就是我們創(chuàng)建LiveData的地方。
2、viewModel.getName()拿到LiveData對(duì)象,observer添加觀察者,this是Lifecycle生命周期組件。
3、當(dāng)數(shù)據(jù)變化setValue時(shí),會(huì)自動(dòng)調(diào)用觀察者的onChanged方法,我們就可以更新UI或其它操作了。
- 其中在理解ViewModel上可不必太追究細(xì)節(jié),理解為創(chuàng)建對(duì)象即可
- 至于observe的參數(shù)this參數(shù),帶入的是Lifecycle,不太理解生命周期請(qǐng)移步Lifecycle
- 為啥用MutableLiveData對(duì)象是因?yàn)镸utableLiveData提供set,get方法。而LiveData只對(duì)外開放get方法,LiveData的set,get代碼如下:
protected void setValue(T value) {
public T getValue() {
3.2、自定義LiveData
public class MyLiveData<T> extends MutableLiveData<T> {
@Override
protected void onActive() {
super.onActive();
Log.d("yink","onActive");
}
@Override
protected void onInactive() {
super.onInactive();
Log.d("yink","onInactive");
}
}
自定義LiveData的時(shí)候,跟我們其它繼承用法一樣。說下onActive和onInactive什么時(shí)候調(diào)用
- onActive 兩個(gè)條件:添加了observe + 生命周期alive。
- onInactive 移除了observe,或者生命周期非alive。
例:點(diǎn)擊home到后臺(tái):onInactive; 重新進(jìn)入頁面:onActive ; 移除observe:onInactive
3.3、轉(zhuǎn)換LiveData
Livecycle給我提供了兩種方法來轉(zhuǎn)換LiveData
Transformations.map
:把LiveData的值改變一下,目的是轉(zhuǎn)換值
Transformations.switchMap
:每次改變值時(shí)提供一個(gè)全新的liveData對(duì)象并監(jiān)聽這個(gè)新的liveData對(duì)象
下面我用相同的例子來講解一下他們的區(qū)別,便于大家理解
我有一個(gè)MutableLiveData<Integer> adressNumber;來表示區(qū)號(hào),然后我們要轉(zhuǎn)換這個(gè)區(qū)號(hào)為當(dāng)前哪個(gè)市區(qū)。于是有下面的代碼
MutableLiveData<Integer> adressNumber;
MutableLiveData<String> adressStringOne = (MutableLiveData<String>) Transformations.map(adressNumber, new Function<Integer, String>() {
@Override
public String apply(Integer input) {
return getAdressString(input);
}
});
MutableLiveData<String> adressStringTwo = (MutableLiveData<String>) Transformations.switchMap(adressNumber, new Function<Integer, LiveData<String>>() {
@Override
public LiveData<String> apply(Integer input) {
MutableLiveData mutableLiveData = new MutableLiveData<String>();
mutableLiveData.setValue(getAdressString(input));
return mutableLiveData;
}
});
private String getAdressString(Integer number) {
if (number == 0755) return "深圳";
return "其它";
}
例子很簡(jiǎn)單,就是輸入?yún)^(qū)號(hào)0755,查詢出來是深圳。
map用法:
1、adressStringOne這個(gè)LiveData的值就是一個(gè)String,通過輸入的0755來轉(zhuǎn)換成”深圳“
2、adressStringOne對(duì)象沒有變,每次監(jiān)聽adressNumber來設(shè)置自己的值
switchMap用法:
1、adressStringTwo這個(gè)LiveData同樣擁有一個(gè)String值,通過輸入的0755來轉(zhuǎn)換成”深圳“
2、adressStringTwo和map用法不同的是,他拿到”深圳”這個(gè)值后,不是直接設(shè)置,而是new一個(gè)新的LiveData<String>,adressStringTwo來監(jiān)聽LiveData<String>變化并且和新的LiveData<String>的值保持同步。
原理
原理也比較簡(jiǎn)單,貼出源碼結(jié)合我上面的例子就很好理解了。
public interface Function<I, O> {
O apply(I input);
}
@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;
}
1、Function.apply只是方便我們自己去轉(zhuǎn)換值
2、MediatorLiveData
對(duì)象繼承自MutableLiveData
它提供的addSource方法可以觀察LiveData對(duì)象,這也就是map和switchMap的關(guān)鍵實(shí)現(xiàn)。讓LiveData可以觀察LiveData
3、傳入source,被觀察者,它一變化就調(diào)用onChanged方法。在onChanged里MediatorLiveData設(shè)置新的值
4、流程簡(jiǎn)單總結(jié)就是:對(duì)象A來觀察B的值,根據(jù)B的變化,A設(shè)置一個(gè)新的值,A觀察B
@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;
}
1、Function.apply
和MediatorLiveData
和上面map一個(gè)用法
2、當(dāng)?shù)谝淮蝬變化,進(jìn)入onChanged,mSource = newLiveData,MediatorLiveData就會(huì)根據(jù)新的newLiveData來監(jiān)聽它的變化,addSource持值同步。
3、當(dāng)?shù)诙蝬變化,進(jìn)入onChanged,mSource = newLiveData根據(jù)java局部變量特性,newLiveData是不同于第一次x變化時(shí)的newLiveData對(duì)象。此時(shí)會(huì)result.removeSource(mSource);移除之前的監(jiān)聽,再重新監(jiān)聽這個(gè)新newLiveData的值,并且addSource保持值同步。
4、switchMapFunction的代碼從頭到尾,result.addSource了兩次,也就是有兩個(gè)監(jiān)聽
5、流程簡(jiǎn)單總結(jié)就是:A觀察B的值,B變化必然創(chuàng)建一個(gè)新的C,A觀察C。所以A同時(shí)觀察B和C,只不過這個(gè)B每次變化會(huì)導(dǎo)致A監(jiān)聽一個(gè)新的C
6、當(dāng)然如果你寫switchMapFunction.apply(x);
實(shí)現(xiàn)的時(shí)候,返回的是同一個(gè)對(duì)象,那么C也不會(huì)變。
3.4、合并多個(gè)LiveData
合并多個(gè)LiveData目的很明確,比如一個(gè)按鈕需要兩個(gè)LiveData狀態(tài)來確定, 你就需要同時(shí)監(jiān)聽兩個(gè)LiveData才行。直接拋出一個(gè)例子,很簡(jiǎn)單就不詳解了。
mediatorLiveData.addSource(addressNumber, new Observer() {
@Override
public void onChanged(Object o) {
Address address = (Address)mediatorLiveData.getValue();
address.setNum((Integer)o);
mediatorLiveData.setValue(address);
}
});
mediatorLiveData.addSource(addressString, new Observer() {
@Override
public void onChanged(Object o) {
Address address = (Address)mediatorLiveData.getValue();
address.setString((String) o);
mediatorLiveData.setValue(address);
}
});
mediatorLiveData.observe(this, new Observer() {
@Override
public void onChanged(Object o) {
}
});
class Address {
Integer num;
String string;
...
}
四、寫在最后
整體來看LiveData還是一個(gè)很簡(jiǎn)單的控件,它的核心思想 = Lifecycle + 觀察者模式。優(yōu)點(diǎn)離不開它的核心思想,簡(jiǎn)單來說生命周期有效性不用我們過多擔(dān)心了,還有就是觀察者模式的優(yōu)點(diǎn)讓我們刷新UI變的更便利,能給我們省去不少邏輯代碼。所以它還是很巧妙的一個(gè)控件。