AndroidJetpack架構組件(四)一文帶你瞭解LiveData(使用篇)

NO IMAGE

本文首發於微信公眾號「後廠村碼農」

前言

在2017年前後,RxJava一直很火,我在Android進階三部曲第一部《Android進階之光》中就介紹了RxJava的使用和原理。谷歌推出的LiveData和RxJava類似,也是基於觀察者,你可以認為LiveData是輕量級的RxJava。起初LiveData並不被看好,隨著谷歌的大力推廣,LiveData也慢慢的進入了大家的視野。一般來說,LiveData很少單獨使用,它更多的和Android Jetpack的其他組件搭配使用,比如和ViewModel。這篇文章就來介紹LiveData的使用。

1.什麼是LiveData

LiveData如同它的名字一樣,是一個可觀察的數據持有者,和常規的observable不同,LiveData是具有生命週期感知的,這意味著它能夠在Activity、Fragment、Service中正確的處理生命週期。

AndroidJetpack架構組件(四)一文帶你瞭解LiveData(使用篇)

LiveData的數據源一般是ViewModel,也可以是其它可以更新LiveData的組件。當數據更新後,LiveData 就會通知它的所有觀察者,比如Activiy。與RxJava的方法不同的是,LiveData並不是通知所有觀察者,它 只會通知處於Active狀態的觀察者,如果一個觀察者處於Paused或Destroyed狀態,它將不會收到通知。
這對於Activiy和Service特別有用,因為它們可以安全地觀察LiveData對象而不用擔心內存洩漏的問題。開發者也不需要在onPause或onDestroy方法中解除對LiveData的訂閱。還有一點需要注意的是一旦觀察者重新恢復Resumed狀態,它將會重新收到LiveData的最新數據。

1.LiveData的基本用法

LiveData是一個抽象類,它的最簡單的實現類為MutableLiveData,這裡舉個最簡單的例子。

public class MainActivity extends AppCompatActivity {
private static final String TAG="MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MutableLiveData<String> mutableLiveData  = new MutableLiveData<>();
mutableLiveData.observe(this, new Observer<String>() {//1
@Override
public void onChanged(@Nullable final String s) {
Log.d(TAG, "onChanged:"+s);
}
});
mutableLiveData.postValue("Android進階三部曲");//2
}
}

註釋1處的observe方法有兩個參數分別是LifecycleOwner和 Observer<T> ,第一個參數就是MainActivity本身,第二個參數新建了一個Observer<String>,在onChanged方法中得到回調。註釋處的postValue方法會在主線程中更新數據,這樣就會得到打印的結果。
D/MainActivity: onChanged:Android進階三部曲

在大多數情況下,LiveData的observe方法會放在onCreate方法中,如果放在onResume方法中,會出現多次調用的問題。除了MutableLiveData的postValue方法,還可以使用setValue方法,它們之前的區別是,setValue方法必須在主線程使用,如果是在工作線程中更新LiveData,則可以使用postValue方法。

2.更改LiveData中的數據

如果我們想要在LiveData對象分發給觀察者之前對其中存儲的值進行更改,可以使用Transformations.map()和Transformations.switchMap(),下面通過簡單的例子來講解它們。

2.1 Transformations.map()

如果想要在LiveData對象分發給觀察者之前對其中存儲的值進行更改,可以使用Transformations.map()。

public class MainActivity extends AppCompatActivity {
private static final String TAG="MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MutableLiveData<String> mutableLiveData  = new MutableLiveData<>();
mutableLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d(TAG, "onChanged1:"+s);
}
});
LiveData transformedLiveData =Transformations.map(mutableLiveData, new Function<String, Object>() {
@Override
public Object apply(String name) {
return name + "+Android進階解密";
}
});
transformedLiveData.observe(this, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d(TAG, "onChanged2:"+o.toString());
}
});
mutableLiveData.postValue("Android進階之光");
}
}

通過Transformations.map(),在mutableLiveData的基礎上又加上了字符串”+Android進階解密”。
打印結果為:
D/MainActivity: onChanged1:Android進階之光
D/MainActivity: onChanged2:Android進階之光+Android進階解密

2.2 Transformations.switchMap()

如果想要手動控制監聽其中一個的數據變化,並能根據需要隨時切換監聽,這時可以使用Transformations.switchMap(),它和Transformations.map()使用方式類似,只不過switchMap()必須返回一個LiveData對象。

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
MutableLiveData<String> mutableLiveData1;
MutableLiveData<String> mutableLiveData2;
MutableLiveData<Boolean> liveDataSwitch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mutableLiveData1 = new MutableLiveData<>();
mutableLiveData2 = new MutableLiveData<>();
liveDataSwitch = new MutableLiveData<Boolean>();//1
LiveData transformedLiveData= Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData<String>>() {
@Override
public LiveData<String> apply(Boolean input) {
if (input) {
return mutableLiveData1;
} else {
return mutableLiveData2;
}
}
});
transformedLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d(TAG, "onChanged:" + s);
}
});
liveDataSwitch.postValue(false);//2
mutableLiveData1.postValue("Android進階之光");
mutableLiveData2.postValue("Android進階解密");
}
}

註釋1處新建一個MutableLiveData<Boolean>()來控制切換並賦值給liveDataSwitch,當liveDataSwitch的值為true時返回mutableLiveData1,否則返回mutableLiveData2。註釋2處將liveDataSwitch的值更新為false,這樣輸出的結果為”Android進階解密”,達到了切換監聽的目的。

3 合併多個LiveData數據源

MediatorLiveData繼承自mutableLiveData,它可以將多個LiveData數據源集合起來,可以達到一個組件監聽多個LiveData數據變化的目的。

public class MainActivity extends AppCompatActivity {
private static final String TAG="MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MutableLiveData<String> mutableLiveData1  = new MutableLiveData<>();
MutableLiveData<String> mutableLiveData2  = new MutableLiveData<>();
MediatorLiveData liveDataMerger = new MediatorLiveData<String>();
liveDataMerger.addSource(mutableLiveData1, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d(TAG, "onChanged1:"+o.toString());
}
});
liveDataMerger.addSource(mutableLiveData2, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d(TAG, "onChanged2:"+o.toString());
}
});
liveDataMerger.observe(this, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d(TAG, "onChanged:"+o.toString());
}
});
mutableLiveData1.postValue("Android進階之光");
}
}

為了更直觀的舉例,將LiveData和MediatorLiveData放到了同一個Activity中。通過MediatorLiveData的addSource將兩個MutableLiveData合併到一起,這樣當任何一個MutableLiveData數據發生變化時,MediatorLiveData都可以感知到。

打印的結果為:
D/MainActivity: onChanged1:Android進階之光

4 拓展LiveData對象

如果觀察者的生命週期處於STARTED或RESUMED狀態,LiveData會將觀察者視為處於Active狀態 。關於如何擴展LiveData,官網的例子是比較簡潔的,如下所示。

public class StockLiveData extends LiveData<BigDecimal> {
private static StockLiveData sInstance;
private StockManager stockManager;
private SimplePriceListener listener = 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) {
stockManager = new StockManager(symbol);
}
@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}
@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}

上面的代碼是一個觀察股票變動的一個例子,對LiveData進行了拓展,實現了LiveData的兩個空方法onActive和onInactive。當Active狀態的觀察者的數量從0變為1時會調用onActive方法,通俗來講,就是當LiveData對象具有Active狀態的觀察者時調用onActive方法,應該在onActive方法中開始觀察股票價格的更新。當LiveData對象沒有任何Active狀態的觀察者時調用onInactive方法,在這個方法中,斷開與StockManager服務的連接。

在Fragment中使用StockLiveData,如下所示。

public class MyFragment extends Fragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
StockLiveData.get(symbol).observe(this, price -> {
// Update the UI.
});
}
}

總結

這篇文章主要介紹了什麼是LiveData,以及LiveData的使用方法,這裡沒有介紹LiveData和ViewModel的結合使用,以及LiveData的原理,這些會在後面的文章進行介紹。

更多的內容請關注我的獨立博客的知識體系:
liuwangshu.cn/system/


這裡不僅分享大前端、Android、Java等技術,還有程序員成長類文章。

AndroidJetpack架構組件(四)一文帶你瞭解LiveData(使用篇)

相關文章

AndroidJetpack架構組件(六)一文帶你瞭解ViewModel的使用和原理

AndroidGradle(一)Gradle的Android插件入門

AndroidGradle(二)簽名配置和依賴管理

AndroidJetpack架構組件(五)一文帶你瞭解LiveData(原理篇)