EventBus 《三》 事件的具体用法及其讲解

来源:互联网 发布:js设置div不可见 编辑:程序博客网 时间:2024/04/30 03:47

Post事件:

直接调用`EventBus.getDefault().post(Event)就可以发送事件,根据Event的类型就可以发送到相应事件的订阅者。

publicvoid post(Object event) {    PostingThreadState postingState = currentPostingThreadState.get();    List<Object> eventQueue = postingState.eventQueue;    eventQueue.add(event);    if (postingState.isPosting) {        return;    } else {        postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();        postingState.isPosting = true;        if (postingState.canceled) {            thrownew EventBusException("Internal error. Abort state was not reset");        }        try {            while (!eventQueue.isEmpty()) {                postSingleEvent(eventQueue.remove(0), postingState);            }        } finally {            postingState.isPosting = false;            postingState.isMainThread = false;            }    }}复制代码可以看到post内使用了`PostingThreadState`的对象,并且是`ThreadLocal`,来看`PostingThreadState`的定义:复制代码finalstaticclass PostingThreadState {    List<Object> eventQueue = new ArrayList<Object>();    boolean isPosting;    boolean isMainThread;    Subscription subscription;    Object event;    boolean canceled;}


主要是有个成员`eventQueue`,由于是ThreadLocal,所以结果就是,每个线程有一个`PostingThreadState`对象,这个对象内部有一个事件的队列,并且有一个成员`isPosting`表示现在是否正在派发事件,当发送事件开始时,会依次取出队列中的事件发送出去,如果正在派发事件,那么post直接把事件加入队列后返回,还有个成员`isMainThread`,这个成员在实际派发事件时会用到,在`postSingleEvent`中会用到。

privatevoid postSingleEvent(Object event, PostingThreadState postingState) throws Error {    Class<? extends Object> eventClass = event.getClass();    List<Class<?>> eventTypes = findEventTypes(eventClass); // 1boolean subscriptionFound = false;    int countTypes = eventTypes.size();    for (int h = 0; h < countTypes; h++) { // 2        Class<?> clazz = eventTypes.get(h);        CopyOnWriteArrayList<Subscription> subscriptions;        synchronized (this) {            subscriptions = subscriptionsByEventType.get(clazz);        }        if (subscriptions != null && !subscriptions.isEmpty()) { // 3for (Subscription subscription : subscriptions) {                postingState.event = event;                postingState.subscription = subscription;                boolean aborted = false;                try {                    postToSubscription(subscription, event, postingState.isMainThread); // 4                    aborted = postingState.canceled;                } finally {                    postingState.event = null;                    postingState.subscription = null;                    postingState.canceled = false;                }                if (aborted) {                    break;                }            }            subscriptionFound = true;        }    }    if (!subscriptionFound) {        Log.d(TAG, "No subscribers registered for event " + eventClass);        if (eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {            post(new NoSubscriberEvent(this, event));        }    }}

来看一下`postSingleEvent`这个函数,首先看第一点,调用了`findEventTypes`这个函数,代码不帖了,这个函数的应用就是,把这个类的类对象、实现的接口及父类的类对象存到一个List中返回.

接下来进入第二步,遍历第一步中得到的List,对List中的每个类对象(即事件类型)执行第三步操作,即找到这个事件类型的所有订阅者向其发送事件。可以看到,**当我们Post一个事件时,这个事件的父事件(事件类的父类的事件)也会被Post,所以如果有个事件订阅者接收Object类型的事件,那么它就可以接收到所有的事件**。

还可以看到,实际是通过第四步中的`postToSubscription`来发送事件的,在发送前把事件及订阅者存入了`postingState`中。再来看`postToSubscription`

privatevoid postToSubscription(Subscription subscription, Object event, boolean isMainThread) {    switch (subscription.subscriberMethod.threadMode) {    case PostThread:        invokeSubscriber(subscription, event);        break;    case MainThread:        if (isMainThread) {            invokeSubscriber(subscription, event);        } else {            mainThreadPoster.enqueue(subscription, event);        }        break;    case BackgroundThread:        if (isMainThread) {            backgroundPoster.enqueue(subscription, event);        } else {            invokeSubscriber(subscription, event);        }        break;    case Async:        asyncPoster.enqueue(subscription, event);        break;    default:        thrownew IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);    }}

这里就用到`ThreadMode`了:

  • 如果是PostThread,直接执行
  • 如果是MainThread,判断当前线程,如果本来就是UI线程就直接执行,否则加入`mainThreadPoster`队列
  • 如果是后台线程,如果当前是UI线程,加入`backgroundPoster`队列,否则直接执行
  • 如果是Async,加入`asyncPoster`队列

BackgroundPoster

 
privatefinal PendingPostQueue queue;publicvoid enqueue(Subscription subscription, Object event) {    PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);    synchronized (this) {        queue.enqueue(pendingPost);        if (!executorRunning) {            executorRunning = true;            EventBus.executorService.execute(this);        }    }}

代码比较简单,其实就是,待发送的事件被封装成了`PendingPost`对象,`PendingPostQueue`是一个`PendingPost`对象的队列,当`enqueue`时就把这个事件放到队列中,`BackgroundPoster`其实就是一个Runnable对象,当`enqueue`时,如果这个Runnable对象当前没被执行,就将`BackgroundPoster`加入EventBus中的一个线程池中,当`BackgroundPoster`被执行时,会依次取出队列中的事件进行派发。当长时间无事件时`BackgroundPoster`所属的线程被会销毁,下次再Post事件时再创建新的线程。

HandlerPoster

`mainThreadPoster`是一个`HandlerPoster`对象,`HandlerPoster`继承自`Handler`,构造函数中接收一个`Looper`对象,当向`HandlerPoster` enqueue事件时,会像`BackgroundPoster`一样把这个事件加入队列中, 只是如果当前没在派发消息就向自身发送Message

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

在`handleMessage`中会依次取出队列中的消息交由`EventBus`直接调用事件处理函数,而`handleMessage`执行所在的线程就是构造函数中传进来的`Looper`所属的线程,在`EventBus`中构造`mainThreadPoster`时传进来的是MainLooper,所以会在UI线程中执行。

AsyncPoster

`AsyncPoster`就简单了,把每个事件都加入线程池中处理

publicvoid enqueue(Subscription subscription, Object event) {    PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);    queue.enqueue(pendingPost);    EventBus.executorService.execute(this);}

Stick Event

通过`registerSticky`可以注册Stick事件处理函数,前面我们知道了,无论是`register`还是`registerSticky`最后都会调用`Subscribe`函数,在`Subscribe`中有这么一段代码:

 

也就是会根据事件类型从`stickyEvents`中查找是否有对应的事件,如果有,直接发送这个事件到这个订阅者。而这个事件是什么时候存起来的呢,同`register`与`registerSticky`一样,和`post`一起的还有一个`postSticky`函数:

if (sticky) {    Object stickyEvent;    synchronized (stickyEvents) {        stickyEvent = stickyEvents.get(eventType);    }    if (stickyEvent != null) {        // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)        // --> Strange corner case, which we don't take care of here.        postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());    }}


当通过`postSticky`发送一个事件时,这个类型的事件的最后一次事件会被缓存起来,当有订阅者通过`registerSticky`注册时,会把之前缓存起来的这个事件直接发送给它。

接下来是事件的优先级及其相应资源的下载地址


0 0
原创粉丝点击