回顾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() } }
下面就是效果图