美文网首页Android
EventBus框架初解

EventBus框架初解

作者: 蓝灰_q | 来源:发表于2017-11-19 17:03 被阅读65次

    EventBus其实解决了这样几个问题:保存订阅者、发布事件、切换线程、粘性事件

    保存订阅者

    在register(this)时,处理运行时注解,根据this找到类和类中的方法,根据方法的Subscribe注解找到订阅事件的那些方法。
    从Subscribe注解中找到指定的线程、优先级、粘滞等;
    从方法参数中找到订阅的事件类eventType;
    生成订阅者Subscription对象,内有订阅的类和方法的引用
    然后用eventType做key,把订阅者存入concurrentHashMap中,因为一个eventType可能有多个订阅者,而且是典型读多写少的场景,所以用CopyOnWriteArrayList来保存这些订阅者。

    发布事件

    在post时,根据eventType,从concurrentHashMap中寻找订阅者。
    会根据父类查找,eventType是根据对象的类和父类一起判断的,所以会根据一个类的列表去查询订阅者。
    会排队处理,为了确保一个接一个地发送事件,post其实是先进入队列Queue,然后每次从队列中弹一个event来处理的,这个队列是个普通的List,实际上作为FIFO处理。

    切换线程

    同一个事件的不同订阅者,可能需要不同的线程去执行。
    在找到订阅者处理时,根据订阅者要求的线程模式,做个switch处理:

            switch (subscription.subscriberMethod.threadMode) {
                case POSTING:
                    invokeSubscriber(subscription, event);
                    break;
                case MAIN:
                    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);
            }
    

    可以看到,有默认、mainThreadPoster、backgroundPoster、asyncHandler四类。
    默认会在当前线程直接invokeSubscriber,传递事件给订阅者。
    mainThreadPoster其实就是一个持有主线程Looper的handler,利用handler消息机制,实现在主线程的handleMessage函数里调用eventbus的invokeSubscriber。
    backgroundPoster和asyncPoster都是Runnable,都是获取eventbus中的ExecutorService来处理,不过
    asyncPoster对于队列没做什么特殊处理,每个事件都会一个线程。
    而backgroundPoster做了入队列的锁同步,在出队列处理时,还可以等待1000毫秒:

    PendingPost pendingPost = queue.poll(1000);
    

    其实就是说,backgroundPoster会尽量复用线程。

    粘滞消息

    一般事件是订阅在先,接收在后,但是有些情况下,事件已经发送,再去订阅时还希望能拿到这个事件,这时候就需要粘性事件。
    粘性事件的注册也是在注解中:

    @Subscribe(sticky = true)
    

    而粘性事件的发送也有专门的函数:

    EventBus.getDefault().postSticky(new MessageEvent("xxx"));  
    EventBus.getDefault().getStickyEvent(MessageEvent.class);
    EventBus.getDefault().removeStickyEvent(stickyEvent); 
    

    粘性事件的实现原理,也是EventBus维持了一个concurrentHashMap类型的stickyEvents,这个Map的key是event.Class,value则是event本身。
    粘性事件的发送有两个入口:
    一是postSticky,每次都会先更新stickyEvents中的数据,然后post这个event。
    二是register,相当于补发事件,实现粘滞效果,具体是在每次register时,会查询stickyEvent集合中,有没有粘性事件,如果有,就补发。

    参考

    EventBus源码分析(三)

    相关文章

      网友评论

        本文标题:EventBus框架初解

        本文链接:https://www.haomeiwen.com/subject/hckpvxtx.html