组件之间的通信LiveDataBus

关于LiveDataBus

① LiveData是Android Architecture Components提出的框架。LiveData是一个能够被观察的数据持有 类,它能够感知并遵循Activity、Fragment或Service等组件的生命周期。正是因为LiveData对组件 生命周期可感知特色,所以能够作到仅在组件处于生命周期的激活状态时才更新UI数据。php

② LiveData须要一个观察者对象,通常是Observer类的具体实现。当观察者的生命周期处于STARTED或 RESUMED状态时,LiveData会通知观察者数据变化;在观察者处于其余状态时,即便LiveData的数据变化了, 也不会通知。git

LiveData的优势

① UI和实时数据保持一致,由于LiveData采用的是观察者模式,这样一来就能够在数据发生改变时得到通知 ,更新UI。github

② 避免内存泄漏,观察者被绑定到组件的生命周期上,当被绑定的组件销毁(destroy)时,观察者会马上 自动清理自身的数据。app

③ 不会再产生因为Activity处于stop状态而引发的崩溃,例如:当Activity处于后台状态时,是不会收到 LiveData的任何事件的。框架

④ 不须要再解决生命周期带来的问题,LiveData能够感知被绑定的组件的生命周期,只有在活跃状态才会通 知数据变化。ide

⑤ 实时数据刷新,当组件处于活跃状态或者从不活跃状态到活跃状态时老是能收到最新的数据。post

⑥ 解决Configuration Change问题,在屏幕发生旋转或者被回收再次启动,马上就能收到最新的数据。this

为何要用LiveDataBus替代EventBus和RxBus

① LiveDataBus的实现及其简单,相对EventBus复杂的实现,LiveDataBus只须要一个类就能够实现。spa

② LiveDataBus能够减少APK包的大小,因为LiveDataBus只依赖Android官方Android Architecture Components组件的LiveData,没有其余依赖,自己实现只有一个类。做为比较,EventBus JAR包大小为 57kb,RxBus依赖RxJava和RxAndroid,其中RxJava2包大小2.2MB,RxJava1包大小1.1MB, RxAndroid包大小9kb。使用LiveDataBus能够大大减少APK包的大小。code

③ LiveDataBus依赖方支持更好,LiveDataBus只依赖Android官方Android Architecture Components 组件的LiveData,相比RxBus依赖的RxJava和RxAndroid,依赖方支持更好。

④ LiveDataBus具备生命周期感知,LiveDataBus具备生命周期感知,在Android系统中使用调用者不须要 调用反注册,相比 EventBus和RxBus使用更为方便,而且没有内存泄漏风险。

LiveDataBus的组成

① 消息 消息能够是任何的Object,能够定义不一样类型的消息,如Boolean、String。也能够定义自定义类型的 消息。

② 消息通道 LiveData扮演了消息通道的角色,不一样的消息通道用不一样的名字区分,名字是String类型的,能够通 过名字获取到一个LiveData消息通道。

③ 消息总线 消息总线经过单例实现,不一样的消息通道存放在一个HashMap中。

④ 订阅 Observer 订阅者经过getChannel获取消息通道,而后调用observe订阅这个通道的消息。

⑤ 发布 setValue postValue 发布者经过getChannel获取消息通道,而后调用setValue或者postValue发布消息。

订阅注册

LiveDataBus.get().with("MainActivity", HuaWei.class).observe(this, 
    new Observer<HuaWei>() {
              @Override
              public void onChanged(@Nullable HuaWei huaWei) {
                  if (huaWei != null)
                      Toast.makeText(MainActivity.this, huaWei.getName(),
                      Toast.LENGTH_SHORT).show();
              }
          });
复制代码
  • 发送消息
HuaWei huaWei = new HuaWei("华为","P30Pro");
        LiveDataBus.get().with("MainActivity",HuaWei.class).postValue(huaWei);
复制代码

LiveDataBus原理图

LiveDataBus 问题出现

  • 对于LiveDataBus的初版实现,咱们发现,在使用这个LiveDataBus的过程当中,订阅者会收到订阅以前发布的消息。对于一个 消息总线来讲,这是不可接受的。不管EventBus或者RxBus,订阅方都不会收到订阅以前发出的消息。对于一个消息总线, LiveDataBus必需要解决这个问题。

LiveDataBus 问题缘由总结

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

LiveDataBus 最终实现

  • LiveDataBus 实现
public final class LiveDataBus {
        
            private final Map<String, MutableLiveData<Object>> bus;
        
            private LiveDataBus() {
                bus = new HashMap<>();
            }
        
            private static class SingletonHolder {
                private static final LiveDataBus LIVE_DATA_BUS = new LiveDataBus();
            }
        
            public static LiveDataBus get() {
                return SingletonHolder.LIVE_DATA_BUS;
            }
            public synchronized <T> MutableLiveData<T> with(String key,Class<T> type){
                if (!bus.containsKey(key)){
                    bus.put(key,new BusMutableLiveData<>());
                }
                return (MutableLiveData<T>) bus.get(key);
            }
        }

复制代码
  • LiveDataBus 反射 使observer.mLastVersion = mVersion
public class BusMutableLiveData<T> extends MutableLiveData<T> {
            @Override
            public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T>
            observer) {
                super.observe(owner, observer);
                try {
                    hook(observer);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        
            /**
             * 反射技术  使observer.mLastVersion = mVersion
             *
             * @param observer ob
             */
            private void hook(Observer<T> observer) throws Exception {
                //根据源码 若是使observer.mLastVersion = mVersion; 就不会走回调
                OnChange方法了,因此就算注册
                //也不会收到消息
                //首先获取liveData的class
                Class<LiveData> classLiveData = LiveData.class;
                //经过反射获取该类里mObserver属性对象
                Field fieldObservers = classLiveData.getDeclaredField("mObservers");
                //设置属性能够被访问
                fieldObservers.setAccessible(true);
                //获取的对象是this里这个对象值,他的值是一个map集合
                Object objectObservers = fieldObservers.get(this);
                //获取map对象的类型
                Class<?> classObservers = objectObservers.getClass(); //获取map对象中全部的get方法 Method methodGet = classObservers.getDeclaredMethod("get", Object.class); //设置get方法能够被访问 methodGet.setAccessible(true); //执行该get方法,传入objectObservers对象,而后传入observer做为key的值 Object objectWrapperEntry = methodGet.invoke(objectObservers, observer); //定义一个空的object对象 Object objectWrapper = null; //判断objectWrapperEntry是否为Map.Entry类型 if (objectWrapperEntry instanceof Map.Entry) { objectWrapper = ((Map.Entry) objectWrapperEntry).getValue(); } if (objectWrapper == null) { throw new NullPointerException("Wrapper can not be null!"); } //若是不是空 就获得该object的父类 Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
                //经过他的父类的class对象,获取mLastVersion字段
                Field fieldLastVersion = classObserverWrapper.getDeclaredField
                ("mLastVersion");
                fieldLastVersion.setAccessible(true);
                Field fieldVersion = classLiveData.getDeclaredField("mVersion");
                fieldVersion.setAccessible(true);
                Object objectVersion = fieldVersion.get(this);
                //把mVersion 字段的属性值设置给mLastVersion
                fieldLastVersion.set(objectWrapper, objectVersion);
            }
        }
        
复制代码
LiveDataBusDemo

感谢

谢谢你们的阅读,想要了解更多,请关注我

GitHub

相关文章
相关标签/搜索