LiveDataBus实现原理#用法详解#LiveData扩展

LiveDataBus实现原理#LiveData源码分析

一、liveDataBus简单实现

public class LiveDataBus {
    private final Map> mBus;

    private LiveDataBus() {
        mBus = new ArrayMap<>();
    }

    private static abstract class SingleHolder {
        private static final LiveDataBus DATA_BUS = new LiveDataBus();
    }

    public static LiveDataBus get() {
        return SingleHolder.DATA_BUS;
    }

    public  MutableLiveData getChannel(String target, Class type) {
        if (!mBus.containsKey(target)) {
            mBus.put(target, new MutableLiveData<>());
        }
        return (MutableLiveData) mBus.get(target);
    }

    public MutableLiveData getChannel(String target) {
        return getChannel(target, Object.class);
    }
}
 
  

到这里我们其实已经实现了liveDataBus的基本功能,我们进行如下测试:
在第一个activity中调用:

LiveDataBus.get().getChannel("myfirst1").setValue("我给你发数据了,你收到了吗");

在第二个activity中注册并接受消息

LiveDataBus.get().getChannel("myfirst1", String.class).observe(this, new Observer() {
            @Override
            public void onChanged(@Nullable String s) {
                Toast.makeText(SecondActivity.this, "我收到了蛋疼的消息" + s, Toast.LENGTH_SHORT).show();
            }
        });

这个时候你会发现在第二个activity打开时会出现toast,但是细心的同学会发现,我是在打开第二个activity之前发的消息,在第二个activity打开的时候订阅的,也就是说,我后订阅却收到了你之前发的消息,那如果你们之前发了几千条消息了,我刚刚订阅,难道要我先处理这几千条数据(这一点很像粘性广播的特性)? 显然,这不是我们想要的效果,我们要的结果是observer在被注册之后才能接收消息,而且接收到的消息也应该是在订阅之后发的消息。
二、liveData源码解析
那么为什么会出现这种情况呢?抱着疑惑我们翻看一下liveData的源码:
LiveDataBus实现原理#用法详解#LiveData扩展_第1张图片
首先我们看到liveData持有了一个ObserverWrapper的集合,那么这个ObserverWrapper是什么东东呢?接着看:
LiveDataBus实现原理#用法详解#LiveData扩展_第2张图片
我们看到ObserverWrapper其实是LiveData的一个内部类,他把观察者observer包裹了,并且记录了当前observer的状态(mActive是否活跃)、上一个版本(mLastVersion)。
我们再看一下我们调用的observe方法:
LiveDataBus实现原理#用法详解#LiveData扩展_第3张图片
在这里我们看到了我们的observer被包裹成了LifecycleBoundObserver,他其实继承了ObserverWrapper。
接下来我们看看我们发送数据时做了些啥:
LiveDataBus实现原理#用法详解#LiveData扩展_第4张图片
当我们调用setValue方法时,它会调用dispatchingValue方法完成:
LiveDataBus实现原理#用法详解#LiveData扩展_第5张图片
接着调用了considerNotify(initiator):
LiveDataBus实现原理#用法详解#LiveData扩展_第6张图片
如上图,我们看到当observer.mLastVersion >= mVersion时方法就直接return了,没有再执行onChanged()方法,所以我们可以猜想我们是不是可以通过控制这两个变量的值来实现我们想要的结果呢?于是乎我们先来捋捋这两个变量
那么mVersion怎么赋值的:

static final int START_VERSION = -1;
private int mVersion = START_VERSION;

@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;//每次我们调用setValue时,mVersion加1
        mData = value;
        dispatchingValue(null);
    }

那么mLastVersion 又是怎么赋值的呢:
LiveDataBus实现原理#用法详解#LiveData扩展_第7张图片
我们看到mLastVersion每次都是赋值为START_VERSION,而这个常量我们在上面看到他的值是-1,而且在上图中我们可以看到在considerNotify方法中每次调用onChanged方法之前,都会把mVersion赋值给observer.mLastVersion。
好看完源码,我们思考一下,我们能不能再创建新的ObserverWrapper的时候,直接把mVersion的值赋给mLastVersion,这样就符合(observer.mLastVersion >= mVersion)这一条件了,就不会再继续执行onChanged方法了。
LiveDataBus实现原理#用法详解#LiveData扩展_第8张图片
好的分析完了,那么怎么做呢,想必很多同学看到这里已经猜到了,那就是反射。
三、hook实现observer只接受订阅之后发送的事件:

/**
 * author : geyuecang
 * date   : 2019/4/4 14:20
 * desc   : desc
 */
public class BusMutableLiveData extends MutableLiveData {

    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        super.observe(owner, observer);
        hook(observer);
    }

    private void hook(Observer observer) {
        Class liveDataClass = LiveData.class;
        try {
            //获取field private SafeIterableMap, ObserverWrapper> mObservers
            Field mObservers = liveDataClass.getDeclaredField("mObservers");
            mObservers.setAccessible(true);
            //获取SafeIterableMap集合mObservers
            Object observers = mObservers.get(this);
            Class observersClass = observers.getClass();
            //获取SafeIterableMap的get(Object obj)方法
            Method methodGet = observersClass.getDeclaredMethod("get", Object.class);
            methodGet.setAccessible(true);
            //获取到observer在集合中对应的ObserverWrapper对象
            Object objectWrapperEntry = methodGet.invoke(observers, observer);
            Object objectWrapper = null;
            if (objectWrapperEntry instanceof Map.Entry) {
                objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
            }
            if (objectWrapper == null) {
                throw new NullPointerException("ObserverWrapper can not be null");
            }
            //获取ObserverWrapper的Class对象  LifecycleBoundObserver extends ObserverWrapper
            Class wrapperClass = objectWrapper.getClass().getSuperclass();
            //获取ObserverWrapper的field mLastVersion
            Field mLastVersion = wrapperClass.getDeclaredField("mLastVersion");
            mLastVersion.setAccessible(true);
            //获取liveData的field mVersion
            Field mVersion = liveDataClass.getDeclaredField("mVersion");
            mVersion.setAccessible(true);
            Object mV = mVersion.get(this);
            //把当前ListData的mVersion赋值给 ObserverWrapper的field mLastVersion
            mLastVersion.set(objectWrapper, mV);

            mObservers.setAccessible(false);
            methodGet.setAccessible(false);
            mLastVersion.setAccessible(false);
            mVersion.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后我们把LiveDataBus重的MutableLiveData替换成自己定义的BusMutableLiveData,Now,轻松加愉快,我们就实现了想要的效果。

你可能感兴趣的:(架构)