×

EventBus

96
wbo4958
2018.03.24 11:20 字数 800

EventBus 是一种 publish/subscribe 事件总线,适用于 Android和Java.

EventBus

EventBus Overview

EventBus 涉及两个步骤,

  • register 就是注册事件接收者,
  • post publish事件。

register(Test.this), 将Test类中所有定义了@subscribe的函数通过反射查找出放到一个subscriptionsByEventType Map中, 该Map的key是Event Type类型,如图中所示,分别为 Bar.class和Foo.class. 而该 Map的 Value对应的是一个List, 也就是说同一种Event Type可以定义多个接收函数, 这些接收函数存放在一个List里,最后保存到Map里。

post(new Bar()), Publish一个Event Type为 Bar对象,从subscriptionsByEventType Map通过Bar.class找到用于接收 Bar 事件的List, 最后对List里所有的方法根据订阅时的规则依次执行。

还有一个比较重要的结构体是 typesBySubscriber 该Map主要是用于记录一个类比如 Test.class 是否已经注册过了。

EventBus调用注册函数的几种方法。

EventBus在Post一个事件类型后,对应注册该类型的接收函数就会被调用,而调用时可以会几种不同的方式,主要是由注册函数定义的线程模型决定.

post -> postSingleEvent -> postSingleEventForEventType -> postToSubscription
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);
        }
    }
  • POSTING
    定义成POSTING的接收函数,当事件发生时,就在EventBus.getDefault().post()所在的线程中调用.

  • MAIN
    如果当前是Main线程, 直接调用该注册方法。如果当前不是Main线程,则将该注册方法通过主线程的Handler post到主线程去执行。

  • MAIN_ORDERED
    MAIN_ORDERED与MAIN的区别在于,不管三七二十一,把注册方法post到主线程中,这样如果当前是主线程的话,注册接收的方法不会立即执行,而是放在主线程所有的Message的最后去执行。

  • BACKGROUND
    如果当前是主线程,则将注册方法 post到background线程中去执行。如果当前是非主线程,则直接调用

  • ASYNC
    Async线程类型,将注册方法post到线程池中去执行。

BACKGROUND与ASYNC的区别

class AsyncPoster implements Runnable, Poster {

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

}
final class BackgroundPoster implements Runnable, Poster {

    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) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

BACKGROUND与ASYNC都继承于Runnable, 执行时都是通过线程池去调用执行,而它们的区别在于,对于ASYNC的方式,都是直接提交线程池直接执行,意思是,如果当前有多个注册的事件都是ASYNC,而这些事件都发生了,那它们都会同时在线程池中被调用。意思是多线程运行。

而BACKGROUND线程,当注册的BACKGROUND事件同时发生时,它们会被enqueue到同一个线程中去依次执行。当前,这个同时是有时间限制,BACKGROUND线程去poll在1s,如果没有事件时,它会退出去, 如果这时BACKGROUND再次发生时,此时BACKGROUND可能运行于线程池中另一个线程,而非之前那个线程,不过所有BACKGROUND的事件都是依次在一个线程中执行,而这一个线程并不是真正意义上的一个线程。

android_opensource
Web note ad 1