LiveData粘性数据自定义

LiveData粘性数据自定义

  • 关键词:kotlin,java,hook,反射,函数默认参数,数据粘性(倒灌)

  • 摘要:

    • LiveData所维护的数据具有粘性(先修改,后订阅,依然可以收到之前的数据),本例采用kotlin与自定义hook函数,提托反射机制动态修改LiveData源代码实现带开关(由程序猿决定是否启动粘性)的LiveData
  • 工程结构:

图片.png

  • 粘性数据的应用场景:需要使用历史数据就直接使用MutableLiveData,但是粘性一般是需要被剔除的(极有可能导致问题)

代码示意:

  • OkLiveDataBusKT

    • 实现细节:

      1. 整体概述:

        • 单例模式 去掉黏性事件(有关闭黏性的开关) KT的版本

          根据函数默认参数,可以由用户指定是否去掉粘性数据

      1. 为什么要采用单例

          object OKLiveDataBusKT {
        复制代码
        • LiveData常作为工具类使用,代码抽离,让工程结构清晰
      1. 为什么要去封装自己的总线:维护一个Map

           private val bus : MutableMap<String, BusMutableLiveData<Any>> by lazy { HashMap() }
        复制代码
        • 在使用LiveData时,一般使用经由装饰器模式改造后的LiveData—>MutableLiveData(LiveData的子类,内部仅提供setValue与postValue)

          • 好处:简化LiveData,代码可追逐性强,使用方便

          • 缺点:

            1. 使用MutableLiveData存放订阅者,自己封装总线维护数据时,是以数据为单位的;
            2. 换而言之,一个MutableLiveData只能维护一条数据; 如果需要对多条数据维护,那么就需要引入MutableMap;
            3. 并且受泛型限制,需要传入所维护数据的泛型;
        • 为什么要使用Map:可以维护多条类型不同的数据

          • key:指代所需要维护的数据

            • 指代需要维护的数据,就是在这个上面加眼睛的:MyLiveData.info.observer(this,{ it(指代了所需要维护的数据)

              }

          • value:存放所维护的具体数据

          • value< Any >:为什么要维护Any

            • 对MutableLiveData进行二次封装原来的MutableLiveData在维护数据时,需要传入所维护的数据类型;因为现在是对一组数据进行维护,每条数据的类型不确定,所以采用Any
        • 为什么要使用懒加载:

          • 这个是kotlin中的特性,需要时才加载,节省资源
        • 为什么懒加载的是一个HashMap:

          • 这个Map本质就是HashMap的二次封装
      2. 为什么要对MutableLiveData进行二次封装:

         class BusMutableLiveData<T> private constructor() : MutableLiveData<T>() {
        复制代码
        • 我们希望实现一个带有数据粘性开关的MutableLiveData
      3. 为什么要传入两个泛型还要继承MutableLiveData:

        • 我们还是采用MutableLiveData,不同点在于,我们将所维护的一组(可以是不同类型)MutableLiveData放到了一个HashMap里面去了;并且当前面的泛型确定,后面的也会跟着改变
        • 继承MutableLiveData:使数据可以被LiveData所维护,还是可以实现MyLiveData.info.observer(this,{it})的能力
      4. 为什么要私有化构造方法:

        • 依然保证其全局单例性,保证外界不能入侵代码,只能在这个工具单例中,进行初始化
      5. 为什么要显示写出此类的次构造函数

           // 次构造
                  constructor(isStick: Boolean) : this() {
                      this.isStick = isStick
                  }
        复制代码
        • 任何一个函数都有主构造函数(默认的),但是当指定了此构造函数,那么就需要在次构造中调用主构造函数
      6. 为什么要重写observe方法

         override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        复制代码
        • 重写系统源码,在调用系统observe的时候,先执行重载的函数
      7. 为什么需要动态修改LiveData源代码

         private fun hook(observer: Observer<in T>) {
        复制代码
        • 使用反射动态修改LiveData源码去掉数据粘性:让LiveData在被观察者中维护的数据的版本号等于其在观察者中的版本号 核心代码:就是去执行这个if语句,就去掉粘性了,

            if (observer.mLastVersion >= mVersion) {
                        return;
                    }
                    observer.mLastVersion = mVersion;
                    //noinspection unchecked
                    observer.mObserver.onChanged((T) mData);
          复制代码
        • 继承关系:

          BusMutableLiveData—》MutableLiveData—》LiveData

  • MainActivity

   class MainActivity : AppCompatActivity() {
      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)
  
          // 如果LiveData默认的黏性,会产生Bug,你就需要剔除黏性
  
          // livedata维护具体的数据
          OKLiveDataBusKT.with("data1", String::class.java,false).value = "粘性数据开启,kotlin版本" 
          OKLiveDataBusJava.getInstance().with("data2", String::class.java).value= "粘性数据,Java版本" // Java版本
  
          // 点击事件,跳转下一个Activity
          val button = findViewById<Button>(R.id.button)
          button.setOnClickListener {
              startActivity(Intent(this, MainActivity2::class.java))
          }
      }
  }
复制代码
  • MainActivity2

      package com.derry.livedatabusandviewbinding.simple1
      
      import android.os.Bundle
      import android.util.Log
      import android.widget.Toast
      import androidx.appcompat.app.AppCompatActivity
      import com.derry.livedatabusandviewbinding.R
      import kotlin.concurrent.thread
      
      
      class MainActivity2 : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_main2)
      
              // Kotlin版本订阅观察者,这个key 相当于是LiveData中所维护的数据的唯一标识符,所以在哪里都要一样
              OKLiveDataBusKT.with("data1", String::class.java).observe(this, {
                  Toast.makeText(this, "Kotlin版本的 观察者:${it}", Toast.LENGTH_SHORT).show()
              })
      
              // Java版本订阅观察者(Java是模拟就剔除黏性的,你自己增加开关)
              OKLiveDataBusJava.getInstance().with("data2", String::class.java).observe(this, {
                  Toast.makeText(this, "Java版本的 观察者:${it}", Toast.LENGTH_SHORT).show()
              })
          }
      }
    复制代码
  • OKLiveDataBusJava

      package com.derry.livedatabusandviewbinding.simple1;
      
      import androidx.annotation.NonNull;
      import androidx.lifecycle.LifecycleOwner;
      import androidx.lifecycle.LiveData;
      import androidx.lifecycle.MutableLiveData;
      import androidx.lifecycle.Observer;
      
      import java.lang.reflect.Field;
      import java.lang.reflect.Method;
      import java.util.HashMap;
      import java.util.Map;
      
      /**
       * 单例模式的 默认是去掉粘性,Java版本;想要开关就自己去加
       */
      public class OKLiveDataBusJava {
      
          // 存放订阅者
          private Map<String, BusMutableLiveData<Object>> bus;
          private static OKLiveDataBusJava liveDataBus = new OKLiveDataBusJava();
      
          private OKLiveDataBusJava() {
              bus = new HashMap<>();
          }
      
          public static OKLiveDataBusJava getInstance() {
              return liveDataBus;
          }
      
          // 注册订阅者
          public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type) {
              if (!bus.containsKey(key)) {
                  bus.put(key, new BusMutableLiveData<>());
              }
              return (BusMutableLiveData<T>) bus.get(key);
          }
      
          /*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 synchronized BusMutableLiveData<Object> with(String target) {
              return with(target, Object.class);
          }*/
      
          public static class BusMutableLiveData<T> extends MutableLiveData<T> {
              @Override
              public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
                  super.observe(owner, observer); // 启用系统的功能  不写就破坏了
      
                  hook(observer);
              }
      
              private void hook(Observer<? super T> observer) {
                  try {
                      // TODO 1.得到mLastVersion
                      // 获取到LivData的类中的mObservers对象
                      Class<LiveData> liveDataClass = LiveData.class;
                      Field mObserversField = liveDataClass.getDeclaredField("mObservers");
                      mObserversField.setAccessible(true);
                      // 获取到这个成员变量的对象
                      Object mObserversObject = mObserversField.get(this);
                      // 得到map对象的class对象
                      Class<?> mObserversClass = mObserversObject.getClass();
                      // 获取到mObservers对象的get方法
                      Method get = mObserversClass.getDeclaredMethod("get", Object.class);
                      get.setAccessible(true);
                      // 执行get方法
                      Object invokeEntry = get.invoke(mObserversObject, observer);
                      // 取到entry中的value
                      Object observerWraper = null;
                      if (invokeEntry != null && invokeEntry instanceof Map.Entry) {
                          observerWraper = ((Map.Entry) invokeEntry).getValue();
                      }
                      if (observerWraper == null) {
                          throw new NullPointerException("observerWraper is null");
                      }
                      // 得到observerWraperr的类对象
                      Class<?> supperClass = observerWraper.getClass().getSuperclass();
                      Field mLastVersion = supperClass.getDeclaredField("mLastVersion");
                      mLastVersion.setAccessible(true);
      
                      // TODO 2.得到mVersion
                      Field mVersion = liveDataClass.getDeclaredField("mVersion");
                      mVersion.setAccessible(true);
      
                      // TODO 3.mLastVersion=mVersion
                      Object mVersionValue = mVersion.get(this);
                      mLastVersion.set(observerWraper, mVersionValue);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
      }
    复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享