EventBus 3.1.1 源码解析

 本文要解决的问题
          1.什么是粘性事件?如何实现的?
          2.Eventbus内部线程调度是如何实现的?
     

什么是粘性事件?如何实现的?
    粘性事件,是指在发送事件之后再订阅该事件也能收到该事件,这就使得我们可以预先处理一些事件,让有消费者时再把这些事件投递给消费者.
```
           发送粘性事件
    public void sticky(View view) {
        EventBus.getDefault().postSticky(new EventBean("abc"));
    }

            接收粘性事件
    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void receiveSoundRecongnizedmsg(EventBean bean) {
          L.i(bean.getName());
    }

```
存储粘性事件
```
  public void postSticky(Object event) {
        synchronized (stickyEvents) {
          //存储
            stickyEvents.put(event.getClass(), event);
        }
        // Should be posted after it is putted, in case the subscriber wants to remove immediately
        post(event);
    }
```
通过源码得知当粘性事件发送之后就会被存储到stickyEvents队列里面,当有相对应的订阅的时候才会收到粘性事件。

```
         //当订阅的事件为粘性时 执行以下方法
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                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);
            }
        }
```
当订阅方法,粘性参数为true的时候,会去检索粘性事件存储队列,当队列有匹配的对象的时候执行订阅方法。
```
 public boolean removeStickyEvent(Object event) {
        synchronized (stickyEvents) {
            Class eventType = event.getClass();
            Object existingEvent = stickyEvents.get(eventType);
            if (event.equals(existingEvent)) {
                stickyEvents.remove(eventType);
                return true;
            } else {
                return false;
            }
        }
    }

```
移除粘性事件(当粘性事件处理过之后,需移除粘性事件,否则这个事件会一直存储在队列里面,每次启动都会执行订阅方法)
我们看到移除粘性事件方法是从stickyEvents队列里面找到匹配的对象,然后移除,此事件就不会被重复执行了。

## Eventbus内部线程调度是如何实现的?
```
public enum ThreadMode {
     // 事件的处理和事件的发送在相同的进程
    POSTING,
    //事件的处理会在UI线程执行
    MAIN,
    //后台进程,处理如保存到数据库
    BACKGROUND
    //异步执行,另起线程操作,事件的处理会在单独的线程执行,主要用于后台线程中耗时操作
    ASYNC
}
```
我们知道eventbus的订阅方法有以上四种线程模式,那么event是如何从发送者的线程切换到接收方的线程的呢。
```
  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 MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(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);
        }
    }
```
由此可以得知eventbus是通过  mainThreadPoster;   backgroundPoster;   asyncPoster的enqueue方法进行线程调度的。
```
public class HandlerPoster extends Handler implements Poster {}

final class BackgroundPoster implements Runnable, Poster {}

class AsyncPoster implements Runnable, Poster {}
```
通过上面代码我们可以得知 mainThreadPoster;   backgroundPoster;   asyncPoster这三个类分别继承自Handler Runnable Runnable,也就是说EventBus线程切换底层是通过Handle的handleMessage()方法回到主线程,通过Runnable的run方法切到子线程。

至此我们已经解决以上两个问题。

你可能感兴趣的:(android)