IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> LiveDataBus学习 -> 正文阅读

[移动开发]LiveDataBus学习

LiveDataBus学习

LiveDataBus组成

  • 消息:消息类型可以是任意类型的Object,也可以是自定义类型的消息
  • 消息通道:是通过LiveData来实现的,这是由于LiveData的生命周期感知和可观察性
  • 消息总线:多个消息通道组成消息总线
  • 发布者发布:发布消息,被观察
  • 订阅者订阅:订阅消息,并进行观察

LiveDataBus的优势

  • 实现简单:相比于EventBus的复杂实现,LiveDataBus只需要一个类即可实现
  • 减少APK大小:相比于RxJava和RxAndroid需要2-3M的依赖包,LiveDataBus只需要Android自带的类即可实现
  • 依赖支持好:LiveDataBus只依赖于Android官方的LiveData,相比于其他实现,依赖方的支持更好
  • 生命周期感知:LiveDataBus通过LiveData实现,具有生命周期感知能力,使用更加方便,且不用担心内存泄漏风险

LiveDataBus的实现

  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> with(String target, Class<T> type) {
            if (!bus.containsKey(target)) {
                bus.put(target, new MutableLiveData<>());
            }
            return (MutableLiveData<T>) bus.get(target);
        }
    
        public MutableLiveData<Object> with(String target) {
            return with(target, Object.class);
        }
    }
    
  2. 使用

    1. 注册订阅

      LiveDataBus.get().with("key", Boolean.class)
          .observe(this, new Observer<Boolean>() {
              @Override
              public void onChanged(@Nullable Boolean aBoolean) {
              }
       });
      
    2. 发送消息

      LiveDataBus.get().with("key").setValue(true)
      

使用问题

订阅者不应该收到订阅之前的消息,这是需要解决的问题

  • 问题原因:当 LifeCircleOwner 的状态发生变化的时候,会调用 LiveData.ObserverWrapper 的 activeStateChanged 函数,如果这个时候 ObserverWrapper 的状态是 active,就会调用 LiveData 的 dispatchingValue。在 LiveData 的 dispatchingValue 中,又会调用 LiveData 的 considerNotify 方法。在 LiveData 的 considerNotify 方法中,如果 ObserverWrapper 的 mLastVersion 小于 LiveData 的 mVersion,就会去回调 mObserver 的 onChanged 方法。而每个新的订阅者,其 version 都是-1,LiveData 一旦设置过其 version 是大于-1的(每次 LiveData 设置值都会使其 version 加1),这样就会导致 LiveDataBus 每注册一个新的订阅者,这个订阅者立刻会收到一个回调,即使这个设置的动作发生在订阅之前。请添加图片描述
  • 核心原因: 对于 LiveData,其初始的 version 是-1,当我们调用了其 setValue或者 postValue,其 vesion 会+1;对于每一个观察者的封装 ObserverWrapper,其初始 version 也为-1,也就是说,每一个新注册的观察者,其 version 为-1;当LiveData 设置这个 ObserverWrapper 的时候,如果 LiveData 的 version 大于 ObserverWrapper 的 version,LiveData 就会强制把当前 value 推送给 Observer。

问题解决

使用Hook进行拦截事件的传输,修改事件传输流程只要调用 setValue 版本号 mVersion 就会加1,此时版本号已经不一致导致 onChange 的调用,触发粘性事件,如果将 mObservers.observer.mLastVersion 修改为 mVersion 当前版本,就会在 mObservers.observer.onChange 调用前,也就是数据变化通知前 return 结束,这样就不调 onChange 方法 mObservers 是 Map 对象,Map 的 item 是键值对,observer 是键值对的 value,反射 Map 获取到 Entry 并获取到 value 也就是observer 继承 MutableLiveData,重写 observe 方法,在注册监听时进行 hook 逻辑。

最终实现

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

    @Override
    public 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<>();
     // 生命周期感知的注册监听处理,去除粘性事件
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
      super.observe(owner, observer);
      try {
        hook(observer);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
     // 非生命周期感知的注册监听处理,去除粘性事件
    @Override
    public void observeForever(@NonNull Observer<? super T> observer) {
      if (!observerMap.containsKey(observer)) {
        observerMap.put(observer, new ObserverWrapper(observer));
      }
      super.observeForever(observerMap.get(observer));
    }
    // 非生命周期感知取消注册监听
    @Override
    public void removeObserver(@NonNull Observer<? super T> observer) {
      Observer realObserver = null;
      if (observerMap.containsKey(observer)) {
        realObserver = observerMap.remove(observer);
      } else {
        realObserver = observer;
      }
      super.removeObserver(realObserver);
    }
    // 去除粘性事件
    private void hook(@NonNull Observer<? super T> observer) throws Exception {
      //get wrapper's version
      //1.得到mLastVersion
      //获取到LivData的类中的mObservers对象
      Class<LiveData> classLiveData = LiveData.class;
      Field fieldObservers = classLiveData.getDeclaredField("mObservers");
      fieldObservers.setAccessible(true);
      //获取到这个成员变量的对象
      Object objectObservers = fieldObservers.get(this);
      //得到map对象的class对象
      Class<?> classObservers = objectObservers.getClass();
      //获取到mObservers对象的get方法
      Method methodGet = classObservers.getDeclaredMethod("get", Object.class);
      methodGet.setAccessible(true);
      //执行get方法
      Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);
      //取到entry中的value
      Object objectWrapper = null;
      if (objectWrapperEntry instanceof Map.Entry) {
        objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
      }
      if (objectWrapper == null) {
        throw new NullPointerException("Wrapper can not be bull!");
      }
      //得到observerWraperr的类对象
      Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
      Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");
      fieldLastVersion.setAccessible(true);
      //get livedata's version
      //2.得到mVersion
      Field fieldVersion = classLiveData.getDeclaredField("mVersion");
      fieldVersion.setAccessible(true);
      //3.mLastVersion=mVersion
      Object objectVersion = fieldVersion.get(this);
      //set wrapper's version
      fieldLastVersion.set(objectWrapper, objectVersion);
    }
  }
}

注册订阅:

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

发送信息:

LiveDataBus.get().with("key_test").setValue(s);   
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-23 11:34:50  更:2021-09-23 11:34:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:58:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码