日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Android LiveData组件详解以及LiveDataBus

發(fā)布時(shí)間:2024/9/30 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android LiveData组件详解以及LiveDataBus 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)載請(qǐng)標(biāo)明出處:https://blog.csdn.net/zhaoyanjun6/article/details/99749323
本文出自【趙彥軍的博客】

一、LiveData簡(jiǎn)介

LiveData 是一個(gè)可以被觀察的數(shù)據(jù)持有類,它可以感知 Activity、Fragment或 Service 等組件的生命周期。簡(jiǎn)單來說,他主要有一下優(yōu)點(diǎn)。

  • 它可以做到在組件處于激活狀態(tài)的時(shí)候才會(huì)回調(diào)相應(yīng)的方法,從而刷新相應(yīng)的 UI,不用擔(dān)心發(fā)生內(nèi)存泄漏
  • 當(dāng) config 導(dǎo)致 activity 重新創(chuàng)建的時(shí)候,不需要手動(dòng)取處理數(shù)據(jù)的儲(chǔ)存和恢復(fù)。它已經(jīng)幫我們封裝好了。
  • 當(dāng) Actiivty 不是處于激活狀態(tài)的時(shí)候,如果你想 livedata setValue 之后立即回調(diào) obsever 的 onChange 方法,而不是等到 Activity 處于激活狀態(tài)的時(shí)候才回調(diào) obsever 的 onChange 方法,你可以使用 observeForever 方法,但是你必須在 onDestroy 的時(shí)候 removeObserver。

回想一下,在你的項(xiàng)目中,是不是經(jīng)常會(huì)碰到這樣的問題,當(dāng)網(wǎng)絡(luò)請(qǐng)求結(jié)果回來的時(shí)候,你經(jīng)常需要判斷 Activity 或者 Fragment 是否已經(jīng) Destroy, 如果不是 destroy,才更新 UI。而當(dāng)你如果使用 Livedata 的話,因?yàn)樗窃?Activity 處于 onStart 或者 onResume 的狀態(tài)時(shí),他才會(huì)進(jìn)行相應(yīng)的回調(diào),因而可以很好得處理這個(gè)問題,不必謝一大堆的 activity.isDestroyed()。接下來,讓我們一起來看一下 LiveData 的使用。

二、使用

LiveData 是一個(gè)抽象類,它的實(shí)現(xiàn)子類有 MutableLiveData,MediatorLiveData。在實(shí)際使用中,用得比較多的MutableLiveData。他常常結(jié)合 ViewModel一起使用。下面,讓我們一起來看一下怎樣使用它?

import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.Observer import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.widget.Button import android.widget.TextViewclass MainActivity : AppCompatActivity() {lateinit var tv: TextViewvar liveData = MutableLiveData<String>() //定義liveDataprivate val changeObserver = Observer<String> { value ->value?.let { tv.text = it }}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)tv = findViewById(R.id.tv1)liveData.value = "123"liveData.observe(this, changeObserver) //注冊(cè)觀察者findViewById<Button>(R.id.cancel).setOnClickListener {liveData.value = "456"}} }

注意事項(xiàng)

必須要從主線程調(diào)用 setValue(T) 方法來更新 LiveData 對(duì)象;如果代碼在工作線程中執(zhí)行, 你可以使用 postValue(T) 方法來更新LiveData對(duì)象

三、LiveDataBus

3.1 為什么要用LiveDataBus替代EventBus和RxBus?

  • LiveDataBus的實(shí)現(xiàn)及其簡(jiǎn)單 相對(duì) EventBus 復(fù)雜的實(shí)現(xiàn),LiveDataBus 只需要一個(gè)類就可以實(shí)現(xiàn)。
  • LiveDataBus可以減小APK包的大小 由于LiveDataBus只依賴 Android 官方 Android Architecture Components 組件的 LiveData ,沒有其他依賴,本身實(shí)現(xiàn)只有一個(gè)類。作為比較,EventBus JAR包大小為57kb,RxBus依賴RxJava和RxAndroid,其中RxJava2 包大小 2.2 MB,RxJava1 包大小 1.1 MB,RxAndroid 包大小 9 kb。使用 LiveDataBus 可以大大減小 APK 包的大小。
  • LiveDataBus依賴方支持更好 LiveDataBus 只依賴 Android 官方 Android Architecture Components 組件的 LiveData ,相比 RxBus 依賴的 RxJava 和 RxAndroid,依賴方支持更好。
  • LiveDataBus具有生命周期感知 LiveDataBus 具有生命周期感知,在 Android 系統(tǒng)中使用調(diào)用者不需要調(diào)用反注冊(cè),相比 EventBus 和 RxBus 使用更為方便,并且沒有內(nèi)存泄漏風(fēng)險(xiǎn)。

3.2 LiveDataBus的設(shè)計(jì)和架構(gòu)

LiveDataBus的組成

  • 消息 消息可以是任何的 Object,可以定義不同類型的消息,如 Boolean 、String 。也可以定義自定義類型的消息。
  • 消息通道 LiveData 扮演了消息通道的角色,不同的消息通道用不同的名字區(qū)分,名字是 String 類型的,可以通過名字獲取到一個(gè)LiveData 消息通道。
  • 消息總線 消息總線通過單例實(shí)現(xiàn),不同的消息通道存放在一個(gè) HashMap 中。
  • 訂閱 訂閱者通過 getChannel 獲取消息通道,然后調(diào)用 observe 訂閱這個(gè)通道的消息。
  • 發(fā)布 發(fā)布者通過 getChannel 獲取消息通道,然后調(diào)用 setValue 或者 postValue 發(fā)布消息。

3.3 LiveDataBus原理圖

3.4 LiveDataBus的實(shí)現(xiàn)

3.4.1 第一個(gè)實(shí)現(xiàn)

public final class LiveDataBus {private final Map<String, MutableLiveData<Object>> bus;private LiveDataBus() {bus = new HashMap<>();}private static class SingletonHolder {private static final LiveDataBus DATA_BUS = new LiveDataBus();}public static LiveDataBus get() {return SingletonHolder.DATA_BUS;}public <T> MutableLiveData<T> getChannel(String target, Class<T> type) {if (!bus.containsKey(target)) {bus.put(target, new MutableLiveData<>());}return (MutableLiveData<T>) bus.get(target);}public MutableLiveData<Object> getChannel(String target) {return getChannel(target, Object.class);} }

短短二十行代碼,就實(shí)現(xiàn)了一個(gè)通信總線的全部功能,并且還具有生命周期感知功能,并且使用起來也及其簡(jiǎn)單:

注冊(cè)訂閱:

LiveDataBus.get().getChannel("key_test", Boolean.class).observe(this, new Observer<Boolean>() {@Overridepublic void onChanged(@Nullable Boolean aBoolean) {}});

發(fā)送消息:

LiveDataBus.get().getChannel("key_test").setValue(true);

我們發(fā)送了一個(gè)名為”key_test”,值為true的事件。

這個(gè)時(shí)候訂閱者就會(huì)收到消息,并作相應(yīng)的處理,非常簡(jiǎn)單。

問題出現(xiàn)
對(duì)于 LiveDataBus 的第一版實(shí)現(xiàn),我們發(fā)現(xiàn),在使用這個(gè) LiveDataBus 的過程中,訂閱者會(huì)收到訂閱之前發(fā)布的消息。對(duì)于一個(gè)消息總線來說,這是不可接受的。無論 EventBus 或者 RxBus,訂閱方都不會(huì)收到訂閱之前發(fā)出的消息。對(duì)于一個(gè)消息總線, LiveDataBus 必須要解決這個(gè)問題。

問題原因總結(jié)
對(duì)于這個(gè)問題,總結(jié)一下發(fā)生的核心原因。對(duì)于 LiveData,其初始的 version是-1,當(dāng)我們調(diào)用了其 setValue 或者 postValue ,其 vesion 會(huì)+1;對(duì)于每一個(gè)觀察者的封裝 ObserverWrapper,其初始 version 也為-1,也就是說,每一個(gè)新注冊(cè)的觀察者,其version 為-1;當(dāng)LiveData設(shè)置這個(gè) ObserverWrapper 的時(shí)候,如果 LiveData 的 version 大于 ObserverWrapper的version,LiveData 就會(huì)強(qiáng)制把當(dāng)前 value 推送給 Observer。

如何解決這個(gè)問題
明白了問題產(chǎn)生的原因之后,我們來看看怎么才能解決這個(gè)問題。很顯然,根據(jù)之前的分析,只需要在注冊(cè)一個(gè)新的訂閱者的時(shí)候把 Wrapper 的 version 設(shè)置成跟 LiveData 的 version 一致即可。

那么怎么實(shí)現(xiàn)呢,看看 LiveData的observe 方法,他會(huì)在步驟1創(chuàng)建一個(gè) LifecycleBoundObserver,LifecycleBoundObserver 是ObserverWrapper 的派生類。然后會(huì)在步驟 2 把這個(gè) LifecycleBoundObserver 放入一個(gè)私有 Map 容器 mObservers 中。無論ObserverWrapper 還是 LifecycleBoundObserver 都是私有的或者包可見的,所以無法通過繼承的方式更改 LifecycleBoundObserver 的 version。

那么能不能從 Map 容器 mObservers 中取到 LifecycleBoundObserver ,然后再更改 version 呢?答案是肯定的,通過查看SafeIterableMap 的源碼我們發(fā)現(xiàn)有一個(gè) protected 的 get方法。因此,在調(diào)用 observe 的時(shí)候,我們可以通過反射拿到LifecycleBoundObserver,再把 LifecycleBoundObserver 的 version 設(shè)置成和 LiveData 一致即可。

LiveDataBus最終實(shí)現(xiàn)

public final class LiveDataBus {private final Map<String, BusMutableLiveData<Object>> bus;private LiveDataBus() {bus = new HashMap<>();}private static class SingletonHolder {private static final LiveDataBus DEFAULT_BUS = new LiveDataBus();}public static LiveDataBus get() {return SingletonHolder.DEFAULT_BUS;}public <T> MutableLiveData<T> with(String key, Class<T> type) {if (!bus.containsKey(key)) {bus.put(key, new BusMutableLiveData<>());}return (MutableLiveData<T>) bus.get(key);}public MutableLiveData<Object> with(String key) {return with(key, Object.class);}private static class ObserverWrapper<T> implements Observer<T> {private Observer<T> observer;public ObserverWrapper(Observer<T> observer) {this.observer = observer;}@Overridepublic void onChanged(@Nullable T t) {if (observer != null) {if (isCallOnObserve()) {return;}observer.onChanged(t);}}private boolean isCallOnObserve() {StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();if (stackTrace != null && stackTrace.length > 0) {for (StackTraceElement element : stackTrace) {if ("android.arch.lifecycle.LiveData".equals(element.getClassName()) &&"observeForever".equals(element.getMethodName())) {return true;}}}return false;}}private static class BusMutableLiveData<T> extends MutableLiveData<T> {private Map<Observer, Observer> observerMap = new HashMap<>();@Overridepublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {super.observe(owner, observer);try {hook(observer);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void observeForever(@NonNull Observer<T> observer) {if (!observerMap.containsKey(observer)) {observerMap.put(observer, new ObserverWrapper(observer));}super.observeForever(observerMap.get(observer));}@Overridepublic void removeObserver(@NonNull Observer<T> observer) {Observer realObserver = null;if (observerMap.containsKey(observer)) {realObserver = observerMap.remove(observer);} else {realObserver = observer;}super.removeObserver(realObserver);}private void hook(@NonNull Observer<T> observer) throws Exception {//get wrapper's versionClass<LiveData> classLiveData = LiveData.class;Field fieldObservers = classLiveData.getDeclaredField("mObservers");fieldObservers.setAccessible(true);Object objectObservers = fieldObservers.get(this);Class<?> classObservers = objectObservers.getClass();Method methodGet = classObservers.getDeclaredMethod("get", Object.class);methodGet.setAccessible(true);Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);Object objectWrapper = null;if (objectWrapperEntry instanceof Map.Entry) {objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();}if (objectWrapper == null) {throw new NullPointerException("Wrapper can not be bull!");}Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");fieldLastVersion.setAccessible(true);//get livedata's versionField fieldVersion = classLiveData.getDeclaredField("mVersion");fieldVersion.setAccessible(true);Object objectVersion = fieldVersion.get(this);//set wrapper's versionfieldLastVersion.set(objectWrapper, objectVersion);}} }

注冊(cè)訂閱

LiveDataBus.get().with("key_test", String.class).observe(this, new Observer<String>() {@Overridepublic void onChanged(@Nullable String s) {}});

發(fā)送消息

LiveDataBus.get().with("key_test").setValue(s);

源碼說明
LiveDataBus 的源碼可以直接拷貝使用,也可以前往作者的 GitHub 倉庫查看下載:
https://github.com/JeremyLiao/LiveDataBus 。

參考資料

Android LiveData 使用詳解
Android消息總線的演進(jìn)之路:用LiveDataBus替代RxBus、EventBus

總結(jié)

以上是生活随笔為你收集整理的Android LiveData组件详解以及LiveDataBus的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。