EventBus源码分析

EventBus简单介绍

  • Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.
  • Android优化的事件总线,简化了活动,片段,线程,服务等之间的通信。较少的代码,更好的质量。
使用EventBus(事件总线 - 事件分发)分成以下几步:
  • 创建事件类
  • 声明订阅方法
  • 注册订阅者
  • 发送订阅事件
  • 注销订阅者

按上面步骤看源码(EventBus源码链接https://github.com/greenrobot/EventBus/)

创建事件类

创建一个普通的实体类就可以了

public class User {
    private String name;
    private int age;
    private String addr;

    public User() {
    }
    ...setter...
    ...getter...

声明订阅方法

这里对订阅的事件做处理

@Subscribe(threadMode= ThreadMode.MAIN)
public voidgetUser(User user){
     textView.setText(user.getName() + "\n" + user.getAge() + "\n" + user.getAddr());//对事件的处理
}

对照源码看Subscribe注解,有三个值。
ThreadMode:订阅方法运行的线程
sticky:是否为粘性事件
priority:优先级
具体的用途,在后面代码中能体现出来。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
    boolean sticky() default false;
    int priority() default 0;
}

注册成为订阅者

先从默认设置开始,看一下是怎样成为订阅者的。

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

单例模式,新建EventBus对象。看看EventBus构造方法。

    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

    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;
    }

采用的是构造者模式,默认设置先不关注。关注一下这几个。

    subscriptionsByEventType = new HashMap<>(); 
    typesBySubscriber = new HashMap<>(); 
    stickyEvents = new ConcurrentHashMap<>(); 
    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    private final Map, CopyOnWriteArrayList>   subscriptionsByEventType;
    private final Map>> typesBySubscriber;
    private final Map, Object> stickyEvents;

subscriptionsByEventType
typesBySubscriber
stickyEvents
具体用来做什么,后面再说。

注册成为订阅者

    public void register(Object subscriber) {
        Class subscriberClass = subscriber.getClass();
        //找到订阅者对象 中的所有 订阅方法
        List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

SubscriberMethod 用来 保存 订阅方法 信息 的一个类

/** 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;
    ...
    List findSubscriberMethods(Class subscriberClass) {
        List 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;
        }
    }

获取订阅者对象中所有 订阅方法。
有两种方式:
1、subscriberMethods = findUsingReflection(subscriberClass);
2、subscriberMethods = findUsingInfo(subscriberClass);
分别看一下。

    private List 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);
    }

通过生成的注解类来获取订阅方法

    private List findUsingReflection(Class subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(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) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            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");
            }
        }
    }

使用反射获取订阅方法

    private List getMethodsAndRelease(FindState findState) {
        List subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        findState.recycle();
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        return subscriberMethods;
    }

返回订阅者中的 所有订阅方法

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;
    }

Subscription是一个同时持有 订阅者、订阅者中的订阅方法 的对象。
下面看看最主要的订阅方法 - subscribe()

    // Must be called in synchronized block
    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<>();
            //以事件类为key、Subscription为value,存到Map中。
            //就是让事件类和订阅者+订阅方法关联起来。
            //保证发送事件时,能找到相应的订阅者+订阅方法。
            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> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            //把订阅者、事件放进typesBySubscriber这个Map中
            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).
                Set, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry, 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);
            }
        }
    }

在subscribe方法中,做了几件事情:
1、subscriptionsByEventType.put(eventType, subscriptions);
以事件类为key、Subscription为value,存到Map中。就是让事件类和订阅者+订阅方法关联起来。保证发送事件时,能找到相应的订阅者+订阅方法。
2、typesBySubscriber.put(subscriber, subscribedEvents);以订阅者为key,事件类为value,存到Map中
3、处理粘性事件(粘性事件:1、允许先发送事件、后注册订阅者 2、粘性事件 只会接收最近一次发送的粘性事件

subscriptionsByEventType、typesBySubscriber、stickyEvents就是前面提到需要关注的三个。


发送订阅事件
    /** Posts the given event to the event bus. */
    public void post(Object event) {
       //获得线程中唯一的postingState
        PostingThreadState postingState = currentPostingThreadState.get();
        //获取事件列表
        List 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;
            }
        }
    }
 
 
    private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
    final static class PostingThreadState {
        // 当前线程的事件队列
        final List eventQueue = new ArrayList();
        // 是否有事件正在分发
        boolean isPosting;
        // 是否为主线程
        boolean isMainThread;
        // 订阅者 + 订阅方法
        Subscription subscription;
        // 待分发的事件
        Object event;
        // 是否被取消
        boolean canceled;
    }
 
 
  • currentPostingThreadState是一个ThreadLocal,保存线程中的变量,具有唯一性。
  • 所以 PostingThreadState postingState = currentPostingThreadState.get();获得了唯一的PostingThreadState
  • PostingThreadState 是定义的一个内部类,用来封装post事件线程的一些信息(在哪个线程中调用post(Object event),就会通过currentPostingThreadState.get()方法去获取PostingThreadState)。
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List> 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));
            }
        }
    }
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class eventClass) {
        CopyOnWriteArrayList 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;
    }
    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        // 获取订阅方法 设置的 运行线程(Subscribe 注解 threadMode)
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                //默认设置,在post事件线程 反射调用订阅方法
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                // 设置为主线程运行
                // 若post 也在主线程 则直接 反射调用订阅方法
                // 否则 添加到mainThreadPoster 的队列中
                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);
        }
    }

获取订阅方法 设置的 运行线程(Subscribe 注解 threadMode)
1、POSTING(默认情况下),直接会在 post事件 线程中 反射调用 订阅方法
2、MAIN 若post事件 也在主线程运行 则直接反射调用 订阅方法。否则添加到mainThreadPoster队列中执行
3、BACKGROUND
4、ASYNC

    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);
        }
    }

反射调用。事件发送流程结束。


注销订阅者
    /** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        // typesBySubscriber是一个HashMap,在注册订阅者的时候,保存了订阅者(key)、事件类(value)。
        // 获得 该 订阅者 订阅的所有 事件类
        List> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            // 遍历所有 事件类
            for (Class eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            // 从HashMap中移除 订阅者
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
    /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class eventType) {
      // 根据 事件类 从subscriptionsByEventType中获取相应的 subscriptions 集合
        List subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            //遍历所有的subscriptions,逐一移除
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

注销订阅者:
1、获取 该订阅者订阅的 所有 事件类
2、从subscriptionsByEventType中 移除subscription
3、从typesBySubscriber中移除 订阅者


下面分别来看一下
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);

HandlerPoster

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;
        }
    }
}

BackgroundPoster

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;
        }
    }

}

AsyncPoster

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);
    }

}

EventBus事件总线的框架,总体思路大致这样,当然,一个如此优秀的框架,还有很多细节需要学习:比如说并发控制、职责分离、设计模式等,以后有机会再慢慢学习。


总结

  • EventBus是采用 发布-订阅 模式,消息的媒介 是 事件类。
  • 注册订阅者时,以key(事件类) 、map(订阅者+订阅方法)保存在一个HashMap中。
  • 发送订阅事件时,会获取线程中的事件列表,根据事件类型 获取所有的订阅者+订阅方法,反射调用订阅方法。
  • 注销订阅者时,移除订阅者。

几点

  • 采用EventBus能很方便进行事件传递,很简洁。但是会导致业务逻辑过于分散,不熟悉代码可能很多地方注意不到。
  • 参考文章http://www.jianshu.com/p/f54514f8cf79
  • 参考文章http://www.jianshu.com/p/bda4ed3017ba(以上两位写的更简单易懂,推荐阅读)
  • 源码https://github.com/greenrobot/EventBus/

你可能感兴趣的:(EventBus源码分析)