Kotlin版去掉黏性事件的LiveData(有关闭黏性事件的开关)

回顾LiveData的使用方式

object MyLiveData {
// 懒加载:用到才加载
val data1 : MutableLiveData<String> by lazy { MutableLiveData<String>() }
​
val data2 : MutableLiveData<String> by lazy { MutableLiveData<String>() }
​
val data10 : MutableLiveData<Boolean> by lazy { MutableLiveData<Boolean>() }
}

class MainActivity : AppCompatActivity() {
​
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
​
•    // ①:订阅观察者 眼睛
•    MyLiveData.data1.observe(this, object: Observer<String> {
•        override fun onChanged(t: String?) {
•            // 更新UI
•        }
•    })
​
•    // ②:触发数据改变
•    thread {
•        Thread.sleep(3000)
•        MyLiveData.data1.postValue("三秒钟后,数据触发改变了")
•    }
}
}
​
​

存放订阅者

有点类似于订阅者

所以我们需要一个存放订阅者,但是里面的数据类型我们并不能写死,可以是String也可以是Int,

这里我们使用Map存储,key是String类型,这样我们上方不管变量名怎么取data1或者data2都可以用String代替

它的value如果直接使用MutableLiveData就无法做到我们的需求,所以我们需要对他进行二次封装

//存放订阅者
private val bus:MutableMap<String,BusMutableLiveData<Any>> by lazy { HashMap() }

我们将会用一个BusMutableLiveData去继承它,数据类型是泛型T,由用户去指定。

我们不想要外界可以new一个新对象,所以我们去私有化主构造

但是Kotlin 主构造私有化,必须写次构造,次构造必须调用主构造

因为我们是否启用黏性是由用户说了算,所以我们需要有一个变量去存储是否启用黏性isStick

class BusMutableLiveData<T>private constructor(): MutableLiveData<T>() {
    var isStick:Boolean=false
    //主构造私有化,必须写次构造,次构造必须调用主构造
    constructor(isStick: Boolean):this(){
        this.isStick=isStick
    }
​
}

居然写到这了,我们就要开始思考如何去除黏性,即当用户调用observe的时候,

先调用我的observe,即将它重载掉,就是我们的hook

再后面我们学习插件化的时候hook我们将会经常用到,这里先做简单的描述

如下图所示,当A要经过起点去往终点使,通过hook吧它勾出来,先执行我们的代码,做我的事情,

再把它放回去执行系统源码

hook是通过反射修改内部源码

 

于是我们就需要重写observe

class BusMutableLiveData<T>private constructor(): MutableLiveData<T>() {
    var isStick:Boolean=false
    //主构造私有化,必须写次构造,次构造必须调用主构造
    constructor(isStick: Boolean):this(){
        this.isStick=isStick
    }
  // 我是先执行
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, observer)// 这句会执行父类的  // 启用系统的功能  不写就破坏了
        
             if (!isStick) {
                hook(observer = observer)
                Log.d("zouxin", "Kotlin版本的 不启用黏性")
            } else {
                Log.d("zouxin", "Kotlin版本的 启用黏性")
            }
    }
}

通过上面的描述我们已经能够很好的看到里面的代码,其实就是判断是否启用黏性,通过hook函数

进行反射拿到我们上一篇文章中提到的

如果我们要去除粘性数据使用反射,使observer.mLastVersion++就可以,使他们相等,就return出去

if (observer.mLastVersion >= mVersion) {
    return;
}

hook函数

那我们开始写hook函数

private fun hook(observer: Observer<in T>){
    //TODO 1.得到mLastVersion
    // 获取到LivData的类中的mObservers对象
    val liveDataClass:Class<LiveData<*>> =LiveData::class.java
​
    val mObserversField:Field = liveDataClass.getDeclaredField("mObservers")
    mObserversField.isAccessible=true// 私有修饰也可以访问
​
    // 获取到这个成员变量的对象  Any == Object
    val mObserversObject: Any = mObserversField.get(this)
​
    // 得到map对象的class对象   private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
    val mObserversClass: Class<*> = mObserversObject.javaClass
​
    // 获取到mObservers对象的get方法   protected Entry<K, V> get(K k) {
    val get: Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
    get.isAccessible = true // 私有修饰也可以访问
​
    //执行get方法
    val invokeEntry: Any = get.invoke(mObserversObject, observer)
​
    // 取到entry中的value   is "AAA" is String    is是判断类型 as是转换类型
    var observerWraper: Any? = null
    if (invokeEntry!=null&&invokeEntry is Map.Entry<*,*>){
        observerWraper=invokeEntry.value
        Log.d("zouxin", "observerWraper")
    }
    if (observerWraper == null) {
        throw NullPointerException("observerWraper is null")
    }
​
    // 得到observerWraperr的类对象
    val supperClass: Class<*> = observerWraper.javaClass.superclass
    val mLastVersion: Field = supperClass.getDeclaredField("mLastVersion")
    mLastVersion.isAccessible = true
​
    // TODO 2.得到mVersion
    val mVersion: Field = liveDataClass.getDeclaredField("mVersion")
    mVersion.isAccessible = true
​
    // TODO 3.mLastVersion=mVersion
    val mVersionValue: Any = mVersion.get(this)
    mLastVersion.set(observerWraper, mVersionValue)
}

分析内部逻辑

第一步就是获取到LivData的类中的mObservers对象

这里我们注意,因为LiveData::class属于kotlin的我们将它转成java的class

第二步我们要拿到,,再上一篇文章提到我们再observe时,进行了二次封装

并最终将他放到mObservers里面去,

   LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

因为它是private修饰我们需要 私有修饰也可以访问

再获取到这个成员变量的对象等价于下面代码,只不过我们用Any进行接收,

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
        new SafeIterableMap<>();

因为它是map对象所以肯定有get方法,我们需要再去拿到get方法,拿到它的value。就是ObserverWrapper

注意这里传入的参数是Any。class

val get: Method = mObserversClass.getDeclaredMethod("get", Any::class.java)

这是因为在它的源码中是泛型指定的

public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {
​
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    Entry<K, V> mStart;
    private Entry<K, V> mEnd;
    // using WeakHashMap over List<WeakReference>, so we don't have to manually remove
    // WeakReferences that have null in them.
    private WeakHashMap<SupportRemove<K, V>, Boolean> mIterators = new WeakHashMap<>();
    private int mSize = 0;
​
    protected Entry<K, V> get(K k) {
        Entry<K, V> currentNode = mStart;
        while (currentNode != null) {
            if (currentNode.mKey.equals(k)) {
                break;
            }
            currentNode = currentNode.mNext;
        }
        return currentNode;
    }

再之后我们需要执行get方法拿到里面的值

但是我们需要判断它是否为空,防止空指针异常

当我们拿到这个值的时候,为什么还要调用 val supperClass: Class<*> = observerWraper.javaClass.superclass

是因为再上面的源码中我们提到它存入的是

LifecycleBoundObserver对象,而它的父类才是我们要的

得到observerWraperr的类对象

最后就拿到了mLastVersion

第二步就是拿到mVersion代码很简单就不过多描述

最后一步,另他们相等

observer.mLastVersion = mVersion //赋值给他对齐

完整代码如下

package com.example.myapplication.simple1

import android.util.Log
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

/**
 * 单例模式 去掉粘性事件(有关闭黏性的开关)
 */
object OKLiveDataBusKT {
    //存放订阅者
    private val bus:MutableMap<String,BusMutableLiveData<Any>> by lazy { HashMap() }

    // 暴露一个函数,给外界注册 订阅者关系
    @Synchronized
    fun <T>with(key:String,type:Class<T>,isStick:Boolean =true ):BusMutableLiveData<T>{
        if (!bus.containsKey(key)){
            bus[key]=BusMutableLiveData(isStick)
        }
        return bus[key]as BusMutableLiveData<T>
    }

    class BusMutableLiveData<T>private constructor(): MutableLiveData<T>() {
        var isStick:Boolean=false
        //主构造私有化,必须写次构造,次构造必须调用主构造
        constructor(isStick: Boolean):this(){
            this.isStick=isStick
        }

        override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
            super.observe(owner, observer)

            if (!isStick) {
                hook(observer = observer)
                Log.d("zouxin", "Kotlin版本的 不启用黏性")
            } else {
                Log.d("zouxin", "Kotlin版本的 启用黏性")
            }
        }
        private fun hook(observer: Observer<in T>){
            //TODO 1.得到mLastVersion
            // 获取到LivData的类中的mObservers对象
            val liveDataClass:Class<LiveData<*>> =LiveData::class.java

            val mObserversField:Field = liveDataClass.getDeclaredField("mObservers")
            mObserversField.isAccessible=true// 私有修饰也可以访问

            // 获取到这个成员变量的对象  Any == Object
            val mObserversObject: Any = mObserversField.get(this)

            // 得到map对象的class对象   private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            val mObserversClass: Class<*> = mObserversObject.javaClass

            // 获取到mObservers对象的get方法   protected Entry<K, V> get(K k) {
            val get: Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
            get.isAccessible = true // 私有修饰也可以访问

            //执行get方法
            val invokeEntry: Any = get.invoke(mObserversObject, observer)

            // 取到entry中的value   is "AAA" is String    is是判断类型 as是转换类型
            var observerWraper: Any? = null
            if (invokeEntry!=null&&invokeEntry is Map.Entry<*,*>){
                observerWraper=invokeEntry.value
            }
            if (observerWraper == null) {
                throw NullPointerException("observerWraper is null")
            }
            Log.d("zouxinobserverWraper", observerWraper.javaClass.toString())
            Log.d("zouxinobserverWraper", observerWraper.javaClass.superclass.toString())

            // 得到observerWraperr的类对象
            val supperClass: Class<*> = observerWraper.javaClass.superclass
            val mLastVersion: Field = supperClass.getDeclaredField("mLastVersion")
            mLastVersion.isAccessible = true

            // TODO 2.得到mVersion
            val mVersion: Field = liveDataClass.getDeclaredField("mVersion")
            mVersion.isAccessible = true

            // TODO 3.mLastVersion=mVersion
            val mVersionValue: Any = mVersion.get(this)
            mLastVersion.set(observerWraper, mVersionValue)
        }
    }
}

再下方我们放入一个java版本

package com.example.myapplication.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();
            }
        }
    }
}

暴露函数,提供注册订阅

那居然我们是私有化,所以我们需要暴露一个函数,给外界注册 订阅者关系

但是我们需要考虑到多线程情况,添加一个同步锁

它的三个参数,第一个参数key:String对应了我们传入的订阅者变量名,

第二个参数type:Class<T>用户只要传入数据类型的class,就可以

第三个参数就是黏性数据的开关,默认值为true,自动启用黏性

// 暴露一个函数,给外界注册 订阅者关系
@Synchronized
fun <T>with(key:String,type:Class<T>,isStick:Boolean =true ):BusMutableLiveData<T>{
    if (!bus.containsKey(key)){
        bus[key]=BusMutableLiveData(isStick)
    }
    return bus[key]as BusMutableLiveData<T>
}

我们里面分析内部逻辑

我们要防止用户重复的添加,如果没有则添加

最终返回我们的成果BusMutableLiveData<T>

尝试使用

package com.example.myapplication
​
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import com.example.myapplication.simple1.OKLiveDataBusJava
import com.example.myapplication.simple1.OKLiveDataBusKT
​
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= "Nine Suns" // Java版本
​
        // 点击事件,跳转下一个Activity
        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            startActivity(Intent(this, MainActivity2::class.java))
        }
    }
}

package com.example.myapplication
​
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.example.myapplication.simple1.OKLiveDataBusJava
import com.example.myapplication.simple1.OKLiveDataBusKT
import kotlin.concurrent.thread
​
class MainActivity2 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
​
        //kotlin版本订阅观察者
        OKLiveDataBusKT.with("data1",String::class.java).observe(this,{
            Toast.makeText(this, "Kotlin版本的 观察者:${it}", Toast.LENGTH_SHORT).show()
            Log.d("zouxin", "Kotlin版本的 观察者:${it}")
        })
​
        // Java版本订阅观察者(Java是模拟就剔除黏性的,你自己增加开关)
        OKLiveDataBusJava.getInstance().with("data2", String::class.java).observe(this, {
            Toast.makeText(this, "Java版本的 观察者:${it}", Toast.LENGTH_SHORT).show()
            Log.d("zouxin", "Java版本的 观察者:${it}")
        })
​
        thread {
            Thread.sleep(6000)
            OKLiveDataBusKT.with("data1", String::class.java).postValue("666")
        }
​
        thread {
            Thread.sleep(12000)
            OKLiveDataBusJava.getInstance().with("data2", String::class.java).postValue("121212")
        }
    }
​
    override fun onResume() {
        super.onResume()
    }
}

下面就是效果图

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin LiveData 是用于 Android 开发的一个特性,它是一个发布-订阅模式的数据源。LiveData 允许你创建可以被观察(即订阅)的数据对象,从而让你的组件知道数据何时发生变化。这使得数据更新更加透明,并且可以轻松地将数据传递给依赖它的组件。 使用 Kotlin LiveData 的基本步骤如下: 1. 创建一个 LiveData 对象:LiveData 对象是你想要发布的数据的公共视图。你可以将任何可变的、可观察的数据(如变量、属性或对象)封装在 LiveData 对象中。 ```kotlin val liveData = MutableLiveData<Int>() ``` 2. 将数据设置为 LiveData 对象:你可以通过调用 LiveData 对象的 set 方法将数据发布出去。 ```kotlin liveData.value = 42 ``` 3. 将 LiveData 对象传递给依赖它的组件:你可以将 LiveData 对象传递给任何需要它的组件,如 ViewModel 或 Activity/Fragment。这样,当 LiveData 中的数据发生变化时,所有订阅该数据的组件都会收到通知。 4. 使用观察者更新 UI:一旦你订阅了 LiveData 对象,你就可以在 UI 中使用观察者来更新 UI。当数据发生变化时,UI 将自动更新。 LiveData 的优点包括: * 它提供了一种简单的方法来处理数据更新,使得组件之间的通信更加清晰和一致。 * 它允许你将数据传递给任何需要它的组件,而无需手动复制或传递数据。 * 它支持多线程操作,可以在异步操作中安全地更新 LiveData 对象。 需要注意的是,LiveData 是用于在后台线程中维护数据的,并且不能被外部观察者修改。因此,如果你需要修改数据并通知外部观察者,你可能需要使用其他方法,如使用 ViewModel 或其他观察者模式实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值