EventBus源码分析及仿EventBus实现

EventBus源码分析

我分析源码一般是从整体来进行分析,对于一些细节的东西,我没有时间也没有能力去分析。

简单使用

导入依赖

implementation'org.greenrobot:eventbus:3.1.1'

定义观察者

public class MyObserver1 {
    public MyObserver1() {
        EventBus.getDefault().register(this);
    }

    @Subscribe
    public void myEvent(MyEvent event){
        System.out.println("我是观察者1,我观察到了");
    }
}
public class MyObserver2 {
    public MyObserver2() {
        EventBus.getDefault().register(this);
    }

    @Subscribe
    public void myEvent(MyEvent event) {
        System.out.println("我是观察者2,我观察到了");
    }
}

定义被观察者和测试

public class MyObserved {
    public MyObserver1 observer1;
    public MyObserver2 observer2;

    public MyObserved() {
        observer1 = new MyObserver1();
        observer2 = new MyObserver2();
    }

    public static void main(String[] args) {
        MyObserved observed = new MyObserved();
        Scanner in = new Scanner(System.in);
        while (true) {
            int code = in.nextInt();
            if (code == 1) {
                observed.sendEvent();
            } else {
                EventBus.getDefault().unregister(observed.observer1);
                EventBus.getDefault().unregister(observed.observer2);
                break;
            }
        }
    }

    public void sendEvent() {
        MyEvent event = new MyEvent();
        EventBus.getDefault().post(event);
    }
}

输出

1
我是观察者1,我观察到了
我是观察者2,我观察到了
1
我是观察者1,我观察到了
我是观察者2,我观察到了
2

具体分析

这里就从上面使用到的方法来进行分析。

入口方法

getDefault()

public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

这里就是采用双重校验并加锁(DCL)的单例模式生成EventBus实例。

注册

register()

public void register(Object subscriber) {
        Class subscriberClass = subscriber.getClass();
        List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

findSubscriberMethods(Class subscriberClass)

List findSubscriberMethods(Class subscriberClass) {
    List subscriberMethods = METHOD_CACHE.get(subscriberClass);//获取缓存
    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    if (ignoreGeneratedIndex) {
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    //。。。省略
}

findUsingReflection(Class subscriberClass)

private List findUsingReflection(Class subscriberClass) {
    //...
        findUsingReflectionInSingleClass(findState);
    //...
}

findUsingReflectionInSingleClass(FindState findState)

private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    }
    for (Method method : methods) {
        Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
        if (subscribeAnnotation != null) {
            Class eventType = parameterTypes[0];
            if (findState.checkAdd(method, eventType)) {
                ThreadMode threadMode = subscribeAnnotation.threadMode();
                findState.subscriberMethods.add(new SubscriberMethod(method, eventType,threadMode,subscribeAnnotation.priority(),subscribeAnnotation.sticky()));
            }
        }
    } 
    //...
}

以上几个方法的大致逻辑就是先看有没有SubscriberMethod的缓存,有的话直接用,没有的话就找出添加了@Subscribe注解的方法。在findUsingReflectionInSingleClass方法里也可以看到很明显的以反射机制处理注解的逻辑。

SubscriberMethod类

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;

    //...
}

从成员变量可以看出这个SubscriberMethod是用来封装观察者的添加了Subscribe注解的方法,观察者有一个观察方法就有一个SubscriberMethod。

最终封装

上面的register方法只看了一部分,还有下面一部分。

public void register(Object subscriber) {
    //...
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

这里将观察者的每个观察方法进行最终封装。

subscribe(Object subscriber, SubscriberMethod subscriberMethod)

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }
    //。。。
}

上面的逻辑就是为了避免二次注册,而我省略的部分可以总结为将Subscription添加进容器里。

Subscription类

final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    //...
}

主要封装了观察者对象和其方法

EventBus有个关键的成员变量:

private final Map, CopyOnWriteArrayList> subscriptionsByEventType;

这个Map以事件类型为键,对应的观察方法的容器为值。

而Subscription封装好了之后就是放入这个Map里的。

发送

post()

public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get();
    List eventQueue = postingState.eventQueue;
    eventQueue.add(event);

    if (!postingState.isPosting) {
        postingState.isMainThread = isMainThread();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

post主要逻辑就是根据传入的事件,根据其事件类型(Class)从subscriptionsByEventType取出对应事件类型的Subscription,然后利用反射机制,调用方法。

仿EventBus实现

这里就根据上面的分析来实现一个简单的EventBus。

构造单例对象

private HashMap, ArrayList> mObserverArrayListHashMap;

private MyEventBus() {
    mObserverArrayListHashMap = new HashMap<>();
}

public static MyEventBus getDefault() {
    return SingletonHolder.SINGLETON;
}

private static class SingletonHolder {
        private static final MyEventBus SINGLETON = new MyEventBus();
    }

这里我采用静态内部类的方式实现单例模式

注册

public void register(Object observer) {
    Class observerClass = observer.getClass();
    List observerMethods = findObserverMethods(observerClass);
    for (ObserverMethod observerMethod : observerMethods) {
        observe(observer, observerMethod);
    }
}

private List findObserverMethods(Class observerClass) {
        List observerMethods = new ArrayList<>();
        for (Method method : observerClass.getDeclaredMethods()) {
            Observe observe = method.getAnnotation(Observe.class);
            if (observe != null) {
                Class eventType = method.getParameterTypes()[0];
                ObserverMethod observerMethod = new ObserverMethod(method, eventType);
                observerMethods.add(observerMethod);
            }
        }
        return observerMethods;
    }
    
private void observe(Object observer, ObserverMethod observerMethod) {
        Class eventType = observerMethod.getEventType();
        Observation observation = new Observation(observer, observerMethod);
        ArrayList observations = mObserverArrayListHashMap.get(eventType);
        if (observations == null) {
            observations = new ArrayList<>();
            mObserverArrayListHashMap.put(eventType, observations);
        } else {
            if (observations.contains(observation)) {
                return;
            }
        }
        observations.add(observation);
    }

两个封装类

class ObserverMethod {
    private Method mMethod;
    private Class mEventType;

    public ObserverMethod(Method method, Class eventType) {
        mMethod = method;
        this.mEventType = eventType;
    }

    public Method getMethod() {
        return mMethod;
    }

    public Class getEventType() {
        return mEventType;
    }
}
class Observation {
    private Object observer;
    private ObserverMethod observerMethod;

    public Observation(Object observer, ObserverMethod observerMethod) {
        this.observer = observer;
        this.observerMethod = observerMethod;
    }

    public Object getObserver() {
        return observer;
    }

    public ObserverMethod getObserverMethod() {
        return observerMethod;
    }
}

发送

public void post(Object event) {
    Class eventType = event.getClass();
    ArrayList observations = mObserverArrayListHashMap.get(eventType);
    if (observations == null) {
        return;
    }
    for (Observation observation : observations) {
        Object observer = observation.getObserver();
        Method method = observation.getObserverMethod().getMethod();
        try {
            method.invoke(observer, event);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

测试

观察者

public class MyObserver1 {
    public MyObserver1() {
        MyEventBus.getDefault().register(this);
    }

    @Observe
    public void myEvent(MyEvent event){
        System.out.println("我是观察者1,我观察到了");
    }
}

public class MyObserver2 {
    public MyObserver2() {
        MyEventBus.getDefault().register(this);
    }

    @Observe
    public void myEvent(MyEvent event){
        System.out.println("我是观察者2,我观察到了");
    }
}

事件

public class MyEvent {
}

被观察者及测试

public class MyObserved {
    public MyObserved() {
        MyObserver1 observer1 = new MyObserver1();
        MyObserver2 observer2 = new MyObserver2();
    }

    public static void main(String[] args) {
        MyObserved observed = new MyObserved();
        Scanner in = new Scanner(System.in);
        while (true) {
            int code = in.nextInt();
            if (code == 1) {
                observed.sendEvent();
            } else {
                break;
            }
        }
    }

    public void sendEvent() {
        MyEvent event = new MyEvent();
        MyEventBus.getDefault().post(event);
    }
}

output:
1
我是观察者1,我观察到了
我是观察者2,我观察到了
1
我是观察者1,我观察到了
我是观察者2,我观察到了
2

Process finished with exit code 0

你可能感兴趣的:(EventBus源码分析及仿EventBus实现)