码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-01 11:38:03      阅读:126      评论:0      收藏:0      [点我收藏+]

标签:android eventbus   android 广播   android eventbus 局部   android fragment e   android eventbus的用   

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`注册时,会把之前缓存起来的这个事件直接发送给它。

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


版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:android eventbus   android 广播   android eventbus 局部   android fragment e   android eventbus的用   

原文地址:http://blog.csdn.net/androidstarjack/article/details/47183751

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!