EventBus原理源码分析和使用

来源:互联网 发布:软件破解授权 编辑:程序博客网 时间:2024/04/28 01:02
前段时间被别人问到关于EventBus的原理,但我确实使用过,用起来也方便简单,一个注册,一个Post就能通知到所有的订阅者Subcriber,其实明明是知道一点点原理的,但是当时就是支支吾吾没有说,太low了,回来大概看了一眼EventBus的源码及实现原谅,现在想把看原代码的一些心得进行记录。OK,我们从Github上面了解一下官方如何介绍这个EventBus吧。
翻译: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,看看我们现在的做法:
</pre><pre code_snippet_id="1679566" snippet_file_name="blog_20160511_1_5619972" name="code" class="java">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的原理基本上就分析到这里了,转载请注明出处,欢迎大家吐槽。










2 0
原创粉丝点击