文章目錄
-
- LiveData介紹
- LiveData優點
- LiveData使用舉例
-
- 基礎用法
- 進階用法
-
- Transformations.map()修改資料源
- Transformations.switchMap()切換資料源
- 源碼解析
-
- 發送資料setValue/postValue
- 注冊觀察者Observer并監聽資料變化
-
- LiveData.observe()
- LiveData.observeForever()
- LiveData實作類MutableLiveData
- 資料切換/修改 Transformations.map()/switchMap()
- 參考
LiveData介紹
LiveData是一種可觀察的資料存儲類。LiveData 具有生命周期感覺能力,遵循其他應用元件(如 Activity、Fragment 或 Service)的生命周期。這種感覺能力可確定 LiveData 僅更新處于活躍生命周期狀态的Observer,非活躍狀态下的Observer不會受到通知。
生命周期狀态可以通過Lifecycle提供,包括DESTROYED、INITIALIZED、CREATED、STARTED、RESUMED,當且僅當生命周期處于STARTED、RESUMED時為活躍狀态,其他狀态是非活躍狀态。
LiveData優點
-
確定界面符合資料狀态
LiveData 遵循觀察者模式。當資料發生變化時,LiveData 會通知 Observer 對象,那麼Observer回調的方法中就可以進行UI更新,即資料驅動。
-
不會發生記憶體洩漏
觀察者會綁定到 Lifecycle 對象,并在其關聯的生命周期遭到銷毀(如Activity進入ONDESTROY狀态)後進行自我清理。
-
不會因 Activity 停止而導緻崩潰
如果觀察者的生命周期處于非活躍狀态(如傳回棧中的 Activity),則它不會接收任何 LiveData 事件。
-
不再需要手動處理生命周期
界面元件隻是觀察相關資料,不會停止或恢複觀察。LiveData 将自動管理所有這些操作,因為它在觀察時可以感覺相關的生命周期狀态變化。
-
資料始終保持最新狀态
如果生命周期變為非活躍狀态,它會在再次變為活躍狀态時接收最新的資料。例如,曾經在背景的 Activity 會在傳回前台後立即接收最新的資料。
-
配置更改時自動儲存資料
如果由于配置更改(如裝置旋轉)而重新建立了 Activity 或 Fragment,它會立即接收最新的可用資料。
-
共享資源
使用單例模式擴充 LiveData 對象以封裝系統服務,以便在應用中共享它們。LiveData 對象連接配接到系統服務一次,然後需要相應資源的任何觀察者隻需觀察 LiveData 對象。
LiveData使用舉例
基礎用法
先上效果圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYWan5SZhF2YiBTMhRTZ3QGNwIjZ4ATYiJGN4U2N0QjM1QGN28CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
在Activity中動态添加了一個Fragment,點選按鈕産生一個1000以内的随機值,并通過LiveData.setValue發送出去,在Fragment中通過LiveData.observe進行資料觀察與接收,可以看到即使Activity中先發送的資料,Fragment中滞後注冊觀察者依然能收到資料,即LiveData發送的是粘性事件。
首先需要保證Activity和Fragment中的LiveData是同一個執行個體:
//LiveDataInstance.kt 使用object來聲明單例模式
object LiveDataInstance {
//MutableLiveData是抽象類LiveData的具體實作類
val INSTANCE = MutableLiveData<String>()
}
Activity中随機生成一個數并通過LiveData.setValue進行發送:
//LiveDataActivity.kt
class LiveDataActivity : AppCompatActivity() {
lateinit var mTextView: TextView
var mFragment: LiveDataFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
mTextView = findViewById(R.id.tv_text)
addLiveDataFragment()
}
fun updateValue(view: View) {
sendData(produceData())
}
//随機更新一個整數
private fun produceData(): String {
val randomValue = (0..1000).random().toString()
mTextView.text = "Activity中發送:$randomValue"
return randomValue
}
//通過setValue發送更新
private fun sendData(randomValue: String) {
LiveDataInstance.INSTANCE.value = randomValue
}
//添加Fragment
fun addFragment(view: View) {
addLiveDataFragment()
}
//移除Fragment
fun removeFragment(view: View) {
delLiveDataFragment()
}
private fun addLiveDataFragment() {
val fragment = supportFragmentManager.findFragmentById(R.id.fl_content)
if (fragment != null) {
Toast.makeText(this, "請勿重複添加", Toast.LENGTH_SHORT).show()
return
}
if (mFragment == null) {
mFragment = LiveDataFragment.newInstance()
}
supportFragmentManager
.beginTransaction()
.add(R.id.fl_content, mFragment!!)
.commitAllowingStateLoss()
}
private fun delLiveDataFragment() {
val fragment = supportFragmentManager.findFragmentById(R.id.fl_content)
if (fragment == null) {
Toast.makeText(this, "沒有Fragment", Toast.LENGTH_SHORT).show()
return
}
supportFragmentManager.beginTransaction().remove(fragment).commitAllowingStateLoss()
}
}
Fragment動态添加到Activity中,并通過LiveData.observe注冊觀察者并監聽資料變化:
//LiveDataFragment.kt
class LiveDataFragment : Fragment() {
lateinit var mTvObserveView: TextView
//資料觀察者 資料改變時在onChange()中進行重新整理
private val changeObserver = Observer<String> { value ->
value?.let {
Log.e(JConsts.LIVE_DATA, "observer:$value")
mTvObserveView.text = value
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.live_data_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mTvObserveView = view.findViewById(R.id.tv_observe)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
//通過LiveData.observe注冊觀察者,監聽資料變化
LiveDataInstance.INSTANCE.observe(this, changeObserver)
}
companion object {
fun newInstance() = LiveDataFragment()
}
}
上面就是一個LiveData的基本用法了,很簡單,Activity/Fragment中共用LiveData執行個體,在Activity中通過點選按鈕生成一個随機數并通過LiveData.setValue發送資料(如果在子線程中發送,需要使用postValue),然後Fragment中通過LiveData.observe注冊觀察者并監聽資料變化。
改一下代碼:
//LiveDataActivity.kt
override fun onStop() {
super.onStop()
val data = produceData()
Log.e(JConsts.LIVE_DATA, "onStop():$data")
sendData(data)
}
//LiveDataFragment.kt
private val changeObserver = Observer<String> { value ->
value?.let {
Log.e(JConsts.LIVE_DATA, "observer:$value")
mTvObserveView.text = value
}
}
點選Home鍵,Activity的onStop會觸發,并通過LiveData.setValue發送資料,看下列印日志:
2021-07-13 17:07:08.662 1459-1459/com.example.jetpackstudy E/LIVEDATA: onStop():742
Activity中在onStop中重新生成了一個随機值并發送了出去,但是在Fragment中的Observer中并沒有收到資料,這是為什麼呢?還記得LiveData的能力嗎,它是能感覺生命周期的,并且隻會更新處于活躍狀态下的Observer(STARTED、RESUMED狀态),是以在onStop中發送的事件,Fragment作為觀察者已經不在活躍狀态下了,并不會收到通知,當我們App切回前台時,Observer重新回到活躍狀态,是以會收到Activity之前發送的事件:
2021-07-13 17:12:47.433 5850-5850/com.example.jetpackstudy E/LIVEDATA: observer:742
如果想讓Observer不管在什麼狀态下都能馬上收到資料變化的通知,可以使用LiveData.observeForever來注冊并監聽資料變化:
//LiveDataFragment.kt
private val changeObserver = Observer<String> { value ->
value?.let {
Log.e(JConsts.LIVE_DATA, "observer:$value")
mTvObserveView.text = value
}
}
//observeForever不管Observer是否處于活躍狀态都會立馬相應資料變化
//注意這裡隻需要傳一個Observer即可,不需要傳入LifecycleOwner,因為不需要考慮Observer是否處于活躍狀态
LiveDataInstance.INSTANCE.observeForever(changeObserver)
override fun onDestroy() {
super.onDestroy()
//需要手動移除觀察者
LiveDataInstance.INSTANCE.observeForever(changeObserver)
}
上述代碼重新實驗,點選Home鍵将App切到背景:
2021-07-13 17:29:56.848 15679-15679/com.example.jetpackstudy E/LIVEDATA: onStop():878
2021-07-13 17:29:56.849 15679-15679/com.example.jetpackstudy E/LIVEDATA: observer:878
可以看到通過LiveData.observeForever注冊的Observer即使不在活躍狀态也是會立馬相應資料變化的,這裡要注意一點,LiveData.observeForever注冊的Observer并不會自動解除注冊,需要我們手動處理。
進階用法
Transformations.map()修改資料源
先上效果圖:
//LiveDataFragment.kt
//資料觀察者 資料改變時在onChange()中進行重新整理
private val changeObserver = Observer<String> { value ->
value?.let {
Log.e(JConsts.LIVE_DATA, "transform observer:$value")
mTvObserveView.text = value
}
}
//Transformations.map()改變接收的data
val transformLiveData = Transformations.map(LiveDataInstance.INSTANCE) { "Transform:$it" }
//觀察者監聽的時候傳入了LifecycleOwner 用以監聽生命周期變化
transformLiveData.observe(this, changeObserver)
可以看到在Activity中發送的資料源是“xxx”,Fragment中經過Transformations.map變換後變成"Transform:xxx",通過Transformations.map()可以對接收的資料源進行修改。
Transformations.switchMap()切換資料源
//LiveDataInstance.kt
object LiveDataInstance {
val INSTANCE = MutableLiveData<String>()
val INSTANCE2 = MutableLiveData<String>()
val SWITCH = MutableLiveData<Boolean>()
}
注:一般LiveData都是與ViewModel結合使用的,本文主要介紹LiveData,是以使用了單例
//LiveDataActivity.kt
mBtnSwitch = findViewById(R.id.btn_switch)
mBtnSwitch.setOnCheckedChangeListener { _, isChecked ->
//發送開關狀态 用以在Transformations.switchMap中切換資料源
LiveDataInstance.SWITCH.value = isChecked
}
//通過setValue發送更新
private fun sendData(randomValue: String, isLeft: Boolean) {
if (isLeft) {
LiveDataInstance.INSTANCE.value = randomValue
} else {
LiveDataInstance.INSTANCE2.value = randomValue
}
}
//LiveDataFragment.kt
//資料觀察者 資料改變時在onChange()中進行重新整理
private val changeObserver = Observer<String> { value ->
value?.let {
Log.e(JConsts.LIVE_DATA, "transform observer:$value")
mTvObserveView.text = value
}
}
//Transformations.switchMap()切換資料源
val switchMapLiveData =
Transformations.switchMap(LiveDataInstance.SWITCH) { switchRight ->
if (switchRight) {
LiveDataInstance.INSTANCE2
} else {
LiveDataInstance.INSTANCE
}
}
switchMapLiveData.observe(this, changeObserverTransform)
例子中有兩個資料源:LiveDataInstance.INSTANCE、LiveDataInstance.INSTANCE2,當Switch開關切換時,通過Transformations.switchMap()可以來回切換資料源,Observer中也會更新對應的資料。
源碼解析
發送資料setValue/postValue
//LiveData.java
//setValue發送資料,隻能在主線程中使用
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
//postValue發送資料,可以在子線程中使用
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
可以看到setValue/postValue都可以發送資料,差別是postValue還可以在子線程中發送資料,本質上postValue通過Handler将事件發送到Main線程中,最終也是調用了setValue發送事件,是以隻看setValue()方法,該方法最後調用了dispatchingValue()方法并傳入了一個參數null,繼續看該方法:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//2、通過observe()的方式會調用這裡
considerNotify(initiator);
initiator = null;
} else {
//1、通過setValue/postValue的方式會調用這裡,周遊所有觀察者并進行分發
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
//觀察者不在活躍狀态 直接傳回
return;
}
//如果是observe(),則是在STARTED、RESUMED狀态時活躍;如果是ObserveForever(),則認為一直是活躍狀态
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//Observer中的Version必須小于LiveData中的Version,防止重複發送
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//回調Observer的onChange方法并接收資料
observer.mObserver.onChanged((T) mData);
}
因為傳入的參數是null,是以最終走到了1處,周遊所有的觀察者并回調Observer的onChange方法接收資料,這樣就完成了一次資料的傳遞。2處是單獨調用一個觀察者并回調其onChange方法接收資料,是執行observe()方法的時候執行的,具體等後面分析。
注冊觀察者Observer并監聽資料變化
LiveData.observe()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
//如果目前觀察者處于DESTROYED狀态,直接傳回
return;
}
//将LifecycleOwner、Observer包裝成LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//ObserverWrapper是LifecycleBoundObserver的父類
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
//如果mObservers中存在該Observer且跟傳進來的LifecycleOwner不同,直接抛異常,一個Observer隻能對應一個LifecycleOwner
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
//如果已經存在Observer且跟傳進來的LifecycleOwner是同一個,直接傳回
if (existing != null) {
return;
}
//通過Lifecycle添加觀察者
owner.getLifecycle().addObserver(wrapper);
}
可以看到最後observe()将Observer加入到Lifecycle裡去了,并通過onStateChanged()回調來監聽LifecycleOwner生命周期的變化,主要看onStateChanged()方法:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//Observer對應的LifecycleOwner是DESTROYED狀态,直接删除該Observer,是以LiveData有自動解除Observer的能力
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
//ObserverWrapper.java
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
//觀察者數量從0變為1時
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
//觀察者數量從1變為0時
onInactive();
}
if (mActive) {
//觀察者為活躍狀态,進行分發
dispatchingValue(this);
}
}
onActive()在觀察者數量從0變為1時執行;onInactive()在觀察者數量從1變為0時執行。最後如果目前觀察者是活躍狀态,直接執行dispatchingValue(this),this是目前ObserverWrapper對象,還記得dispatchingValue()方法嗎,前面講這個方法的時候留了個疑問,這裡就會執行前面講的該方法裡2處的代碼,用以分發事件并在Observer的onChange()方法裡接收并處理事件。
LiveData.observeForever()
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
observeForever()中不需要傳LifecycleOwner參數,因為observeForever()認為是一直活躍的狀态,是以不需要監聽LifecycleOwner的生命周期,最後是直接執行了wrapper.activeStateChanged(true)方法,後續的邏輯跟上面observe()一樣了。這裡注意一點,observeForever()注冊的觀察者當處于DESTROYED的時候并不會自動删除,需要手動删除之。
LiveData實作類MutableLiveData
public class MutableLiveData<T> extends LiveData<T> {
public MutableLiveData(T value) {
super(value);
}
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
MutableLiveData是抽象類LiveData的具體實作類。
資料切換/修改 Transformations.map()/switchMap()
//Transformations.java
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;
}
從源碼的注釋上,看到了這麼一句話
This method is analogous to {@link io.reactivex.Observable#map}
,哦,原來用法是跟RxJava中的Map操作符類似。第一個參數是源LiveData< X>,第2個參數是個Funtion< X,Y>,目的就是将LiveData< X>變換為LiveData< Y>,然後再重新發送事件。map()方法裡new了一個MediatorLiveData并執行了addSource()方法,看看這個方法怎麼實作的:
//MediatorLiveData.java
public class MediatorLiveData<T> extends MutableLiveData<T> {
private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
//将源LiveData及Observer包裝成Source
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
//如果源LiveData中已經有Observer且跟傳進來的不一緻,直接抛異常
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();
}
}
@MainThread
public <S> void removeSource(@NonNull LiveData<S> toRemote) {
Source<?> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
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() {
//通過observeForever添加觀察者,有變動時就會回調下面的onChange()方法
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);
}
}
}
}
首先将源LiveData及Observer包裝成Source,經過了幾次判斷,最後執行到了Source#plug()方法,裡面通過observeForever添加觀察者,有變動時就會回調Source#onChange()方法,而這個方法裡又會回調傳進來的Observer#onChange()方法,即執行到了map()中傳入的Observer的onChange()方法,裡面通過setValue發送了轉換之後的資料格式,這樣就完成了整個的資料轉換格式。那麼再看switchMap()就簡單了:
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;
}
可以看到switchMap()中實作方式跟map()基本一緻,隻不過map()改變的是資料,而switchMap()改變的是資料源,可以對資料源進行切換。Transformations還有個distinctUntilChanged方法簡單看一下:
public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) {
final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>();
outputLiveData.addSource(source, new Observer<X>() {
boolean mFirstTime = true;
@Override
public void onChanged(X currentValue) {
final X previousValue = outputLiveData.getValue();
if (mFirstTime
|| (previousValue == null && currentValue != null)
|| (previousValue != null && !previousValue.equals(currentValue))) {
mFirstTime = false;
outputLiveData.setValue(currentValue);
}
}
});
return outputLiveData;
}
也很簡單,隻有當資料源發生改變時,Observer才會相應,即發送重複的資料時,除第一次之外的資料都會被忽略。
最後畫一下類圖:
參考
【1】https://developer.android.com/topic/libraries/architecture/livedata?hl=zh_cn
【2】Android LiveData 使用詳解