转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/99749323
本文出自【赵彦军的博客】

一、LiveData简介

LiveData 是一个可以被观察的数据持有类,它可以感知 Activity、Fragment或 Service 等组件的生命周期。简单来说,他主要有一下优点。

  • 它可以做到在组件处于激活状态的时候才会回调相应的方法,从而刷新相应的 UI,不用担心发生内存泄漏
  • 当 config 导致 activity 重新创建的时候,不需要手动取处理数据的储存和恢复。它已经帮我们封装好了。
  • 当 Actiivty 不是处于激活状态的时候,如果你想 livedata setValue 之后立即回调 obsever 的 onChange 方法,而不是等到 Activity 处于激活状态的时候才回调 obsever 的 onChange 方法,你可以使用 observeForever 方法,但是你必须在 onDestroy 的时候 removeObserver。

回想一下,在你的项目中,是不是经常会碰到这样的问题,当网络请求结果回来的时候,你经常需要判断 Activity 或者 Fragment 是否已经 Destroy, 如果不是 destroy,才更新 UI。而当你如果使用 Livedata 的话,因为它是在 Activity 处于 onStart 或者 onResume 的状态时,他才会进行相应的回调,因而可以很好得处理这个问题,不必谢一大堆的 activity.isDestroyed()。接下来,让我们一起来看一下 LiveData 的使用。

二、使用

LiveData 是一个抽象类,它的实现子类有 MutableLiveDataMediatorLiveData。在实际使用中,用得比较多的MutableLiveData。他常常结合 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)  //注册观察者findViewById<Button>(R.id.cancel).setOnClickListener {liveData.value = "456"}}
}

注意事项

必须要从主线程调用 setValue(T) 方法来更新 LiveData 对象;如果代码在工作线程中执行, 你可以使用 postValue(T) 方法来更新LiveData对象

三、LiveDataBus

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

  • LiveDataBus的实现及其简单 相对 EventBus 复杂的实现,LiveDataBus 只需要一个类就可以实现。
  • LiveDataBus可以减小APK包的大小 由于LiveDataBus只依赖 Android 官方 Android Architecture Components 组件的 LiveData ,没有其他依赖,本身实现只有一个类。作为比较,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 系统中使用调用者不需要调用反注册,相比 EventBus 和 RxBus 使用更为方便,并且没有内存泄漏风险。

3.2 LiveDataBus的设计和架构

LiveDataBus的组成

  • 消息 消息可以是任何的 Object,可以定义不同类型的消息,如 Boolean 、String 。也可以定义自定义类型的消息。
  • 消息通道 LiveData 扮演了消息通道的角色,不同的消息通道用不同的名字区分,名字是 String 类型的,可以通过名字获取到一个LiveData 消息通道。
  • 消息总线 消息总线通过单例实现,不同的消息通道存放在一个 HashMap 中。
  • 订阅 订阅者通过 getChannel 获取消息通道,然后调用 observe 订阅这个通道的消息。
  • 发布 发布者通过 getChannel 获取消息通道,然后调用 setValue 或者 postValue 发布消息。

3.3 LiveDataBus原理图

3.4 LiveDataBus的实现

3.4.1 第一个实现

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);}
}

短短二十行代码,就实现了一个通信总线的全部功能,并且还具有生命周期感知功能,并且使用起来也及其简单:

注册订阅

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

发送消息

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

我们发送了一个名为”key_test”,值为true的事件。

这个时候订阅者就会收到消息,并作相应的处理,非常简单。

问题出现
对于 LiveDataBus 的第一版实现,我们发现,在使用这个 LiveDataBus 的过程中,订阅者会收到订阅之前发布的消息。对于一个消息总线来说,这是不可接受的。无论 EventBus 或者 RxBus,订阅方都不会收到订阅之前发出的消息。对于一个消息总线, LiveDataBus 必须要解决这个问题。

问题原因总结
对于这个问题,总结一下发生的核心原因。对于 LiveData,其初始的 version是-1,当我们调用了其 setValue 或者 postValue ,其 vesion 会+1;对于每一个观察者的封装 ObserverWrapper,其初始 version 也为-1,也就是说,每一个新注册的观察者,其version 为-1;当LiveData设置这个 ObserverWrapper 的时候,如果 LiveData 的 version 大于 ObserverWrapper的version,LiveData 就会强制把当前 value 推送给 Observer。

如何解决这个问题
明白了问题产生的原因之后,我们来看看怎么才能解决这个问题。很显然,根据之前的分析,只需要在注册一个新的订阅者的时候把 Wrapper 的 version 设置成跟 LiveData 的 version 一致即可。

那么怎么实现呢,看看 LiveData的observe 方法,他会在步骤1创建一个 LifecycleBoundObserver,LifecycleBoundObserver 是ObserverWrapper 的派生类。然后会在步骤 2 把这个 LifecycleBoundObserver 放入一个私有 Map 容器 mObservers 中。无论ObserverWrapper 还是 LifecycleBoundObserver 都是私有的或者包可见的,所以无法通过继承的方式更改 LifecycleBoundObserver 的 version。

那么能不能从 Map 容器 mObservers 中取到 LifecycleBoundObserver ,然后再更改 version 呢?答案是肯定的,通过查看SafeIterableMap 的源码我们发现有一个 protected 的 get方法。因此,在调用 observe 的时候,我们可以通过反射拿到LifecycleBoundObserver,再把 LifecycleBoundObserver 的 version 设置成和 LiveData 一致即可。

LiveDataBus最终实现

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);}}
}

注册订阅

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

发送消息

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

源码说明
LiveDataBus 的源码可以直接拷贝使用,也可以前往作者的 GitHub 仓库查看下载:
https://github.com/JeremyLiao/LiveDataBus 。

参考资料

Android LiveData 使用详解
Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus

Android LiveData组件详解以及LiveDataBus相关推荐

  1. android 广播的权限,Android四大组件详解之BroadcastReceiver广播接收者

    Android四大组件详解---BroadcastReceicer广播接收者 广播有两个角色,一个是广播发送者,另一个是广播接收者. 广播按照类型分为两种,一种是全局广播,另一种是本地广播 全局广播: ...

  2. 【Android 应用开发】Android - 按钮组件详解

    总结了Android中常用的按钮用法 示例源码下载地址 : -- CSDN :  http://download.csdn.net/detail/han1202012/6852091 -- GitHu ...

  3. Android运行ListView的代码,Android ListView组件详解及示例代码

    Android 列表组件 ListView 列表组件是开发中经常用到组件,使用该组件在使用时需要为它提供适配器,由适配器提供来确定显示样式和显示数据. 下面看一个例子: 新建一个项目Lesson8_L ...

  4. Android Gallery组件详解(转)

    http://www.eoeandroid.com/forum.php?mod=viewthread&tid=182297&reltid=39709&pre_thread_id ...

  5. Android笔记——四大组件详解与总结

    android四大组件分别为activity.service.content provider.broadcast receiver. -------------------------------- ...

  6. Android基础四大组件详解

    Android四大组件详解 博主接触Android开发将近一年,从最初的JavaSE开始,到Android基础,一直学的糊糊涂涂,最近想整理一番 android基础, 顺便把自己的学习开发经验分享给大 ...

  7. Android Lifecycle 生命周期组件详解

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/99695779 本文出自[赵彦军的博客] 一.Lifecycle简介 为什么要引进 ...

  8. Android应用开发—Intent组件详解

    转载自:Android中Intent组件详解 Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件. Intent本身是定义为一个类别(Class),一个Intent对象表达一个目的 ...

  9. android组件模板,提高效率必备神器 ---- Android Studio模板详解

    原标题:提高效率必备神器 ---- Android Studio模板详解 Android Studio模板大家应该很熟悉,你新建一个project或者module的时候,AS会帮你提供几个选项供你选择 ...

最新文章

  1. Spring Boot 整合Redis 实现缓存
  2. 直接可以拿去用的正则验证表达式
  3. CentOS 6.5上安装Zabbix 2.4.8
  4. usage: git remote add [options] name url -f, --fetch fetch the remote branches ...
  5. 关于Windows XP SP3 的 FAQ
  6. robot framework 使用四:分层设计和截图以及注意事项
  7. 产品设计:一层分类与多层分类模式的感悟
  8. 图像处理:透镜畸变及校正模型
  9. 农行运营合规管理心得体会_老员工写诗讲述农行40年运营风采
  10. 计算机启动过程过程图,计算机启动过程图文详解(一)----计算机初始化启动过程...
  11. linux c硬盘序列号,linux下获得硬盘序列号的c源代码
  12. 【工作日报】2019年7月 前端开发工作日报汇总
  13. b站pink老师JavaScript的DOM案例代码——模拟京东快递单号查询
  14. java min函数_Java Math min()用法及代码示例
  15. matlab求二阶电路图,MATLAB实验MATLAB数值计算:二阶电路时域研究
  16. 从照片中读取经纬度信息
  17. 深度探索C++对象模型pdf
  18. sizzle.js学习笔记利用闭包模拟实现数据结构:字典(Map)
  19. 楼氏硅麦SPH0641LM4H-1
  20. 怎么关闭excel出现的microsoft office 自定义安装程序提示

热门文章

  1. ddr传输 pl ps_Vitis ZYNQ开发秘籍 PS 端任意控制 VGA 显示画面最终实现
  2. 域用户绑定计算机批量设置,Windows 2008 AD域账户与计算机名批量绑定
  3. java模拟浏览器不关闭会话_JSP实现浏览器关闭cookies情况下的会话管理
  4. 型热电偶阻值温度对照表_如何选用温度传感器
  5. mysql 语句_如何记录MySQL执行过的SQL语句
  6. 五十七、教用Python中的turtle海龟画图(下篇)
  7. django表与表之间的关系
  8. 三十一、Scrapy爬取百度图片
  9. 幸福指数测试软件,测试你和ta的幸福指数能不能爆表
  10. 剔除异常值栅格计算器_基于数据流的异常检测: Random Cut Forest