EventBus原理源码分析和使用

 
 

有段时间面试被问到关于EventBus的原理,但我确实使用过,用起来也方便简单,一个注册,一个Post就能通知到所有的订阅者Subcriber,其实明明是知道一点点原理的,但是当时就是支支吾吾没有说,太low了,回来大概看了一眼EventBus的源码及实现原谅,现在想把看原代码的一些心得进行记录。


OK,我们从Github上面了解一下官方如何介绍这个EventBus吧。
EventBus原理源码分析和使用_第1张图片
翻译:
    EventBus是一个事件发布/订阅总线,有效适用于Android系统平台。
    EventBus...
    .组件之间的通信更加简单
        。针对在事件的发送者和订阅者之间进行解耦
        。非常好的运用在Activitys、Fragments和后台线程
        。避开了联系紧密易出错的依赖关系和容易出错生命周期
    .使你的代码更加简洁
    .快
    .瘦(小于50K的jar包)
    .有100,00,000+的app使用了EventBus

简单翻译就是这样一个意思,翻译不好请多担待,但是尽管翻译很差,但是大体的原理描述和工作是体现出来了。

我是直接从Github不上下载的最新的源代码进行研究的,在这里我想提出一个注意的地方,之前的旧一点的版本3.0之前的版本,订阅者的事件通知的方法都是通过开发者遵守命名约定,这样没有安全性,容易出错,很不方便开发,但是后来3.0开始使用注解的方式对事件的方法的声明。

如下是之前的版本使用的命名约定的方式。
1、onEvent
2、onEventMainThread
3、onEventBackgroundThread
4、onEventAsync

现在最新版本订阅者的事件方法名称可以随意声明,只要在方法的上简单的加上一些相关的注解就可以了,而且注解是必须加上的,否则会抛出Runtime异常。

OK,看看我们现在的做法:
package com.example.eventbustest;
import org.greenrobot.eventbus.EventBus;
public class MainActivity extends Activity implements OnClickListener {
    private Button mButton;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_layout);
            final Intent  intent= new Intent(this,EventBusTestService.class);
            startService(intent);
            EventBus.getDefault().register(this);
            mButton = (Button) findViewById(R.id.button1);
            mButton.setOnClickListener(this);
        }

        @Subscribe(threadMode=ThreadMode.ASYNC)
        public void onEventReceive(EventBusMsg msg){
            Log.d("ZHG-EventBusTest","MainActivity.onEventReceive , msg = "+msg.msg +" , MainThreadID = "+this.getMainLooper().getThread().getId()+" , currentTreadID = "+Thread.currentThread().getId());
        }

        @Override
        public void onClick(View view) {
                switch (view.getId() ) {
                case R.id.button1:
             EventBus.getDefault().post(new EventBusMsg("Test Message!!!!"));
                    break;
                default:
                    break;
                }
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            EventBus.getDefault().unregister(this);
        }
}


package com.example.eventbustest;
import org.greenrobot.eventbus.EventBus;
public class EventBusTestService extends Service {
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @Subscribe(threadMode=ThreadMode.BACKGROUND)
    public void onEventBusMsgReceive(EventBusMsg msg){
        Log.d("ZHG-EventBusTest","EventBusTestService.onEventBusMsgReceive , msg = "+msg.msg +" , MainThreadID = "+this.getMainLooper().getThread().getId()+" , currentTreadID = "+Thread.currentThread().getId());
    }
}

从上面的示例代码就能看出,最新的版本再也不用那么麻烦的去记住什么约定的方法怎么写,不用再去背了,现在只要自己命名成自己喜欢的方法名,然后简单的加上注解就行,而且还可以设置线程模式,比如是是否在主线程、子线程等。

OK,上面是针对使用上的一些变化进行一个温馨提示,接下来直接奔入主题,看源代码把。

1. EventBus.getDefault();开始
入口EventBus.getDefault();开始,这里我还是很喜欢这样的静态单例对象获取方法名,我本人也很喜欢使用单例的时候,取名getDefault()。
/** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

很简单,就是一个单例设计代码,看看构造方法。

 /**
     * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
     * central bus, consider {@link #getDefault()}.
     */
    public EventBus() {
        this(DEFAULT_BUILDER);
    }

    EventBus(EventBusBuilder builder) {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }
构造方法中创建了几个容器,用来装各种订阅者信息的,很关键的几个成员我们需要注意,mainThreadPoster 、backgroundPoster 、asyncPoster ,这个几个是后来post消息的时候,用的到的,就是利用他们将消息在不同的线程发送出去,达到在不同线程中执行的效果。
mainThreadPoster:很显然是一个自定义扩展后的Handler,在构造的时候传入的是主线的Looper,所以它是一个主线程的对应的Handler。
这里之间先看看这个Handler的代码吧:

 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;

import android.os.Handler;

final class HandlerPoster extends Handler {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
} 

没错,就是传入一个MainThread的Looper,创建了一个主线程的Handler,毋庸置疑,通过他发送的事件消息,都是在主线中执行的。

backgroundPoster : 那这个是什么呢,我们来看看代码。

 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;

import android.util.Log;

/**
 * Posts events in background.
 * 
 * @author Markus
 */
final class BackgroundPoster implements Runnable {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }
}
很明显他是一个实现了Runnable 的对象,所以它的载体肯定是一个子线程,是给某子线程执行具体任务的。

asyncPoster :再来看看这个,这个听名字就感觉已经知晓大部分信息了,异步Poster,可定也是在单独线程中post任务的。
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;


/**
 * Posts events in background.
 * 
 * @author Markus
 */
class AsyncPoster implements Runnable {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    AsyncPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        eventBus.getExecutorService().execute(this);
    }

    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }
}
所以这里就不用多说了,也是一个实现了Runnable 的对象,一定也是被子线程执行的具体任务。

所以最后我们都能看到上面三段代码两个共同的两行代码:
eventBus.invokeSubscriber(pendingPost);  这行代码其实就是在使用反射调用订阅的者的事件方法。
 eventBus.getExecutorService().execute(this); 这行代码很明显就是把时间提交给一个空闲的线程去执行。
当然HandlerPoster 就除外了,当然他是使用sendMessage的方式去去执行一个具体的事件,其实对应的也是 eventBus.getExecutorService().execute(this);这行代码。

OK,这里我们就浅层次的分析到这里,我们回到主线,继续。


2.register(Object subcriber)注册订阅者

我们通过EventBus的getDefualt()方法获取了一个EventBus的对象,然后就可以通过他来注册地订阅者了,接下来就看看EventBus的register(Object subcriber)方法是如果实现的呢?
 /**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * <p/>
     * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
     * The {@link Subscribe} annotation also allows configuration like {@link
     * ThreadMode} and priority.
     */
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

OK,从上面的代码中,我们可以看到调用了 subscriberMethodFinder对象的findSubscriberMethods(subscriberClass);方法,subscriberMethodFinder这个对象呢,我们其实都不用太关心,可以把他当作一个管理获取、查找、订阅者和订阅者Method的对象,然后通过它我们就能拿到一个List集合,这个集合存储的都是SubscriberMehtod对象,这里有必要去追求一下SubscriberMehtod是个什么东西呢,我们来看看吧:
 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;

import java.lang.reflect.Method;

/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;

    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other instanceof SubscriberMethod) {
            checkMethodString();
            SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
            otherSubscriberMethod.checkMethodString();
            return methodString.equals(otherSubscriberMethod.methodString);
        } else {
            return false;
        }
    }

    private synchronized void checkMethodString() {
        if (methodString == null) {
            // Method.toString has more overhead, just take relevant parts of the method
            StringBuilder builder = new StringBuilder(64);
            builder.append(method.getDeclaringClass().getName());
            builder.append('#').append(method.getName());
            builder.append('(').append(eventType.getName());
            methodString = builder.toString();
        }
    }

    @Override
    public int hashCode() {
        return method.hashCode();
    }
}
很明显从这个SubscriberMethod 类的成员变量就能看出来,这是一个封装了一个关于Method的信息的对象,这些信息包括   final Method method(反射方法对象)对象、 final ThreadMode threadMode(线程模式)对象、final Class<?> eventType(事件类型,方法中的参数)对象、final int priority(权限) 标记、  final boolean sticky(是否sticky类型)标记、 String methodString(方法描述字串) 用来提高两个SubscriberMethod对象比较效率和准确性的。
所以这类就这么简单,就是封装了一个Mehtod的全部信息的。

接下来代码主线往下走。
我们来看一下findSubscriberMethods方法,是如何获取到订阅者的所有方法信息的,直接看方法。
 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass+ " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

从上面的代码可以看的出,一开始 METHOD_CACHE这个集合是空的,获取的时候为空,逻辑会往下走,ignoreGeneratedIndex经过打印默认初始是为false的,所以下一步会走subscriberMethods = findUsingInfo(subscriberClass); OK,直接来看findUsingInfo(subscriberClass);方法。

  private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
 findState.subscriberInfo = getSubscriberInfo(findState); 根据打印,获取到的为null,
所以会走   findUsingReflectionInSingleClass(findState);我们也来看看这个方法的实现。

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers();
     if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                    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()));
                        }
                    }
                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException("@Subscribe method " + methodName +
                            "must have exactly 1 parameter but has " + parameterTypes.length);
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }
所以通过上面的代码,很明显就可以看出,是通过反射拿到每一个方法的修饰符信息,注解信息,参数信息,从上面的代码很明显就知道,我们的订阅方法必须有且只有一个参数,否则会抛出异常的,而且订阅方法必须是public修饰的,而且不是静态、不是抽象方法,否者也会抛出异常的,最后将合法的订阅方法都存到了一个 findState.subscriberMethods集合中了,最后在findUsingReflectionInSingleClass(findState);的调用方发处调用了  
return getMethodsAndRelease(findState);返回了出去了一个 List<SubscriberMethod>集合,这里需要稍微提醒一个地方就是,我们应该都发现了findUsingInfo(Class<?> subscriberClass) 方法中的倒数第四行findState.moveToSuperclass(); 看看这个方法吧.

void moveToSuperclass() {
            if (skipSuperClasses) {
                clazz = null;
            } else {
                clazz = clazz.getSuperclass();
                String clazzName = clazz.getName();
                /** Skip system classes, this just degrades performance. */
                if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                    clazz = null;
                }
            }
        }

这个方法主要是获取当前Class对象的父类(有可能是抽象类或者接口),这样在findUsingInfo(Class<?> subscriberClass) 方法while中循环的获取到每一级Class对象中所有方法信息。

OK,findSubscriberMethods(...)方法就分析到这里,主线接着往下走,回到register方法中,往下看。

然后我们能看到一个for循环的遍历。
 synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }

遍历每一个SubscriberMethod对象,遍历到每一个SubscriberMethod对象之后,调用EventBus的  subscribe(subscriber, subscriberMethod); 方法,那我们就直接来看这个方法。

 // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList<Subscription> 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);
            }
        }

        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > 
subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

一开始就取出了eventType,然后就创建了一个Subscription对象,这里又需要解释一下这个对象是个什么玩意了,直接贴代码吧。
 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
package org.greenrobot.eventbus;

final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    /**
     * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
     * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
     */
    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
    }
}

其实就是很简单的一个对象,我们可以看做一个简单的java bean就好了,他的功能就是封装了一个订阅者实体对象(  final Object subscriber;)和上面我们解释过的,一个Mehtod信息的封装类( final SubscriberMethod subscriberMethod;)。

继续回到主线,我们可以看到,会把EventType和Subscriptions关联起来,很好理解,可以想象的到,我们Post一个事件的时候,一般会带一个事件类型,也就是post方法中的参数。
而一个EventType可能对应很多个方法和对象,然后就把他们存储起来了,源代码体现如下:
 Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList<Subscription> 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);
            }
        }
然后把一个个的新new出来的 Subscription添加了 subscriptions中,而subscriptions又和evetType关联起来了。添加新new出来的Subscription的时候,它会根据事件方法当时声明的时候,设置的priority注解信息,当priority的放在List的队列前面。
 int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

再往下走,就是用实体对象和EventType关联了,这个也不难理解,我们可以理解为,一个实体对象可以写很多个订阅方法,但是没一个订阅方法可能会是不同的EventType(订阅方法的参数类型),所以最后把 eventType添加到了 subscribedEvents之中。
 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
最后一部分的代码是处理Sticky事件的逻辑,我们知道EventBus是可以调用成员方法
来postSticky(Object event)方法来提交一个事件。 主要判断 subscriberMethod的sticky是否为true ,如果是,就从 stickyEvents集合中 获取所有相同事件类型的且设置了sticky属性的订阅者和订阅方法,然后就调用 checkPostStickyEventToSubscription(newSubscription, stickyEvent);方法 将事件发送出去了。

OK,到这里基本上register模块都解释的差不多了,上面我们也看到,各种事件对象、方法对象、和订阅者对象都已经封存起来,可以等待post事件的时候,将事件发送出去。
3. post(Object event) 发布订阅事件

Ok我们继续往下分析关于事件post的时候的实现原理。
我们知道我们在拿到EventBus的实例单例对象的时候,可以简单的就调用的他的post刚发,将一个特定的订阅事件类型发送出去,订阅者的订阅方法就能被回调了,我们来直接看这个方法吧。
 /** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            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;
            }
        }
    }

首先从 currentPostingThreadState( LocalThread)中获取一个与当前线程关联的 PostingThreadState对象,这个对象很简单,其实就是一个记录一个线程事件post状态的实体,可以稍微看看他的代码。
 /** For ThreadLocal, much faster to set (and get multiple values). */
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;
    }

没错就是这么简单,其成员也很好理解,eventQueue 很明显就是一个事件队列,isPosting 这个boolean类型的标记只要就是记录当先线程的事件发布状态,isMainThread主要就是标记当前线程是否为主线程,event事件类型、canceled是否取消post。

首先判断状态,假如下载正在post事件的时候,就不在接受post其他事件了,我们直接分析if语句块里面的代码吧,如果事件队列为空的话,就结束post过程,方法执行结束。
否则进入 postSingleEvent(eventQueue.remove(0), postingState);方法中,然后每次都是获取事件队列中的栈顶的一个事件,注意是使用的remove(0)的方式来获取,直接来看postSingleEvent(Object event, PostingThreadState postingState)方法吧。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
             subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

首先我们知道 eventInheritance的值是为true的,所以会先调用llookupAllEventTypes(eventClass)获取eventClass所有父类的后者接口类型的class对象,存到eventTypes 集合中,这里就不贴出lookupAllEventTypes(eventClass)的代码实现了,因为他的代码很简单,主要就是想上获取父类或者接口类型的class对象,因为比如父类或者接口为Car,BMW extends Car,这些都会被获取出来,记住是eventClass的父类和接口的calss对象哦,然后挨个遍历evnetClass对象。
for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
             subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}

然后调用了 postSingleEventForEventType(event, postingState, clazz);方法,我们直接看这个方法。

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }
OK,我们看到,从subscriptionsByEventType中取出一个subscriptions 对象,我们应该还有印象,前面我们讲过,说事件类型和事件订阅者关联起来了,一个订阅者可以实现多个订阅方法,接收不同事件类型,所以事件类型和订阅者关联起来, 将所有订阅者保存成集合,和事件类型关联了,Ok遍历subscriptions  ,然后调用postToSubscription(subscription, event, postingState.isMainThread);方法去post事件给订阅者。我们直接看这个方法。

 private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

所以上面的代码已经很明显了,就是根据ThreadMode来在不同的线程中发布事件,第一种   case POSTING: 是默认方式下的,表示在当前线程中执行,也就是在事件post所在线程中执行,我们看到它是直接调用  invokeSubscriber(subscription, event)方法去执行了,看看这个方法吧。
 void invokeSubscriber(Subscription subscription, Object event) {
        try {
    subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

我们看到,代码很简单,就一句话,利用发射的方式去执行了,其他的都是异常捕获。

接着看第二种    case MAIN:很明显是在主线程中执行的 我们看这个case下的实现方式。
if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
  }

很好理解,如果当前已经是在主线程中,就直接跟第一种方式一样,直接在当前线程中执行就OK了,如果当前不是主线程,那么只能通过主线程的Handler来发送handler事件消息到主线程去执行了,使用mainThreadPoster将事件加入执行队列,mainThreadPoster我们在一开始的时候我们讲过,他们的实现也很简单,这个具体怎么发送和执行可以去看看,但是他们最后都是调用EventBus的invokeSubscriber(subscription, event);方法来执行的。

第三种 case BACKGROUND: 很明显,就是在后台子线程中执行了,看看这个case下的代码实现吧。
if (isMainThread) {
               backgroundPoster.enqueue(subscription, event);
           } else {
               invokeSubscriber(subscription, event);
    }
也很简单,直接判断当前是否为主线程,如果主线程的话,就直接使用 backgroundPoster来将事件加入执行队列,
backgroundPoster我们在前面做过铺垫,他就是一个Runnable的实现体,接着调用了它自己的enqueue方法,我们稍微提一下这方法。

 public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                eventBus.getExecutorService().execute(this);
            }
        }
    }

最后线程执行,就调用了
backgroundPoster的run方法。

 @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

他最后是通过queue.poll(1000);取出一个事件,将事件交个了EventBus中线程池来执行,从而达到了
backgroundPost的效果,也就是子线程执行的效果。


但是我们这里应该需要注意一个地方,那就是
queue.enqueue(pendingPost);这个将事件的入队操作,这里还是有必要看一下 queue这个队列是个什么样的实现方式。
final class BackgroundPoster implements Runnable {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                eventBus.getExecutorService().execute(this);
            }
        }
    }

我们看到 queue 是一个PendingPostQueue类型的实体成员变量。我们直接贴上这个类的代码来看看。
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)

package org.greenrobot.eventbus;

final class PendingPostQueue {
    private PendingPost head;
    private PendingPost tail;

    synchronized void enqueue(PendingPost pendingPost) {
        if (pendingPost == null) {
            throw new NullPointerException("null cannot be enqueued");
        }
        if (tail != null) {
            tail.next = pendingPost;
            tail = pendingPost;
        } else if (head == null) {
            head = tail = pendingPost;
        } else {
            throw new IllegalStateException("Head present, but no tail");
        }
        notifyAll();
    }

    synchronized PendingPost poll() {
        PendingPost pendingPost = head;
        if (head != null) {
            head = head.next;
            if (head == null) {
                tail = null;
            }
        }
        return pendingPost;
    }

    synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
        if (head == null) {
            wait(maxMillisToWait);
        }
        return poll();
    }

}
从上面的代码我们可以看出,poll和enqueue 都加上 synchronized ,他就是模拟了一个事件队列,enqueue就是将事件入队的动作,当然还模拟了一个事件的队列的队头队尾和next,首先上面代码一开始head为和tail应该都为null,所以会执行如下代码。
             head = tail = pendingPost;
将当前队列的头尾都设置为 pendingPost(当前事件),然后调用notifyAll()方法,通知线程去执行任务,就是把任务交给EventBus中声明的线程池来执行,最后调用到了run方法了,在run方法中调用了 queue.poll(1000);来一个事件,看看poll(int maxMillisToWait)方法吧。

 synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
        if (head == null) {
            wait(maxMillisToWait);
        }
        return poll();
    }
也是很简单啊,直接判断队头是否为空,如果为空就让线程先等1000毫秒,所以最后只有在enqueue被调用,加入新的事件后,notifyAll唤醒线程去调用无参数的重载方法来取出事件返回出去。

synchronized PendingPost poll() {
        PendingPost pendingPost = head;
        if (head != null) {
            head = head.next;
            if (head == null) {
                tail = null;
            }
        }
        return pendingPost;
    }
方法也很简单,首先直接把head赋值给一个新的 pendingPost变量,再判断如果head不为空,直接把下一个next事件复制给head,典型的先进先出队列,然后返回pendingPost。

其实到这里其实也有两个很重要的知识点,队列概念的巧妙是使用,先进先出方式的使用,还有一个是生产者和消费者的概念。
回归主线,判断如果不是主线程,就刚好,直接执行事件就可以了,看最后一种
case ASYNC:
这种其实跟 BACKGROUND一样的执行方式,因为asyncPoster本身也是一个Runnable的实现体,最后也调用了enqueue方法把任务交给了EventBus中的线程池来执行,具体代码基本和BACKGROUND的分析一样的。但是这个和BACKGROUND是有区别的,它是任何时候都要在子线程中执行的.





整个EventBus的 原理基本上就分析到这里了,转载请注明出处,欢迎大家吐槽。










你可能感兴趣的:(github,源码,面试,EventBus,EventBus源码分析)