Android EventBus3.0使用及源码解析

Posted 一口仨馍

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android EventBus3.0使用及源码解析相关的知识,希望对你有一定的参考价值。

本文已授权微信公众号《非著名程序员》原创首发,转载请务必注明出处。

叨了个叨

最近因为换工作的一些琐事搞的我一个头两个大,也没怎么去学新东西,实在是有些愧疚。新项目用到了EventBus3.0,原来只是听说EventBus的鼎鼎大名,一直没仔细研究过。趁着周末有些时间,研究下代码,也算没有虚度光阴。

EventBus GitHub : https://github.com/greenrobot/EventBus

EventBus3.0简介

EventBus是greenrobot出品的一个用于android中事件发布/订阅的库。以前传递对象可能通过接口、广播、文件等等,尤其像同一个Activity两个Fragment之间采用接口传递对象,十分的麻烦,而且耦合度较高。使用EventBus之后,这些将不再是问题。盗用GiHub上EventBus的一张图。

可以看到,发布者(Publisher)使用post()方法将Event发送到Event Bus,而后Event Bus自动将Event发送到多个订阅者(Subcriber)。这里需要注意两个地方:(1)一个发布者可以对应多个订阅者。(2)3.0以前订阅者的订阅方法为onEvent()onEventMainThread()onEventBackgroundThread()onEventAsync()。在Event Bus3.0之后统一采用注解@Subscribe的形式,具体实现方式见下文。

EventBus3.0的使用

新建两个Activity,花3s扫一下即可。代码如下:

public class MainActivity extends Activity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 注册EventBus
        EventBus.getDefault().register(this);
        startActivity(new Intent(this,SecondActivity.class));
    

    @Override
    protected void onDestroy() 
        super.onDestroy();
        // 反注册EventBus
        EventBus.getDefault().unregister(this);
    

    // 主线程调用
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void eventBusMain(String str)
        Log.i("TAG", "MAIN:"+str+" Thread="+Thread.currentThread().getId());
    

    // 1.发布线程为主线程,新开线程调用
    // 2.发布线程为子线程,发布线程调用
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void eventBusBg(String str)
        Log.i("TAG", "BACKGROUND:"+str+" Thread="+Thread.currentThread().getId());
    

    // 在发布线程调用,默认值
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void eventBusPosting(String str)
        Log.i("TAG", "POSTING:"+str+" Thread="+Thread.currentThread().getId());
    

    // 每次都新开线程调用
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void eventBusAsync(String str)
        Log.i("TAG", "ASYNC:"+str+" Thread="+Thread.currentThread().getId());
    


public class SecondActivity extends Activity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        EventBus.getDefault().post("from second activity mainThread: info");
        Log.i("TAG", "Post thread="+Thread.currentThread().getId());
        new Thread(new Runnable() 
            @Override
            public void run() 
                EventBus.getDefault().post("from second activity childThread: info");
                Log.i("TAG", "Post thread="+Thread.currentThread().getId());
            
        ).start();
    

MainActivityonCreate()/onDestroy()中分别注册/反注册EventBus。然后写了四个测试ThreadMode的方法,调用时机注释的很清楚,就不赘述了。最后在SecondActivity的主线程和子线程中分别调用Post()方法,注意,这里Post()方法的参数为Object类型,这也就意味着我们传递任何对象都是可以的,例如JavaBeanList<E>等等都是可以的,这里为了方便演示直接传递了String。Log信息如下:


第一张图中发布者发送线程为主线程,即Post thread = 1,在订阅者收到消息时,ThreadMode = MainThreadMode = Posting的方法都在主线程调用,ASYNCBACKGROUND都新开了线程。图二对比注释同理。

除此之外,Subscribe注解还支持prioritysticky属性。priority设置接收者的优先级,默认值为0。优先级高的方法先被调用,在方法调用完成后可以调用EventBus.getDefault().cancelEventDelivery(event) ;终止优先级低的方法的调用。sticky为粘性事件,默认为关闭状态。能够收到订阅之前发送到的最后一条消息,并且发送的方法不再是post()而是postSticky()

EventBus3.0源码解析

EventBus是Very的好用。耦合度大大的降低,而且代码十分优雅。它是怎么就做到了这么优雅的呢?知其然,知其所以然。下面就开始一步步的分析。

注解标签Subscribe

对注解不了解的同学可以看下这篇博客。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Subscribe 
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * If true, delivers the most recent sticky event (posted with
     * @link EventBus#postSticky(Object)) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread (@link ThreadMode), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different @link ThreadModes! */
    int priority() default 0;


public enum ThreadMode 

    POSTING,

    MAIN,

    BACKGROUND,

    ASYNC

注解Subscribe在运行时解析,且只能加在METHOD上。其中有三个方法,threadMode()返回类型ThreadMode为枚举类型,默认值为POSTINGsticky()默认返回false,priority()默认返回0。

1. Register流程

EventBus#getDefault()

public EventBus() 
    this(DEFAULT_BUILDER);

public static EventBus getDefault() 
    if (defaultInstance == null) 
        synchronized (EventBus.class) 
            if (defaultInstance == null) 
                defaultInstance = new EventBus();
            
        
    
    return defaultInstance;

EventBus采用双重校验锁设计为一个单例模式,奇怪的在于虽然设计为单例模式,但是构造方法确实public类型,这不是坑爹嘛!难道greenrobot在设计EventBus获取实例方法的时候在打LOL,一不小心打错了?原来啊,EventBus默认支持一条事件总线,通常是通过getDefault()方法获取EventBus实例,但也能通过直接new EventBus这种最简单的方式获取多条事件总线,彼此之间完全分开。设计之思想不禁让人拍案叫绝。

EventBus#register()

 public void register(Object subscriber) 
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) 
        for (SubscriberMethod subscriberMethod : subscriberMethods) 
            subscribe(subscriber, subscriberMethod);
        
    

首先得到订阅者的报名.类名,即哪个具体类注册。然后调用subscriberMethodFinder.findSubscriberMethods(subscriberClass),从方法名和返回值来看,findSubscriberMethods()的作用应该是遍历查找订阅者中所有的订阅方法。

SubscriberMethodFinder#findSubscriberMethods()

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) 
    // 查找缓存
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) 
        // 缓存中有则直接返回
        return subscriberMethods;
    
    // 默认false
    if (ignoreGeneratedIndex) 
        subscriberMethods = findUsingReflection(subscriberClass);
     else 
        subscriberMethods = findUsingInfo(subscriberClass);
    
    if (subscriberMethods.isEmpty()) 
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
     else 
        // 加入缓存
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    

注意subscriberMethods.isEmpty(),如果注册了EventBus,但却没有使用注解Subscribe是会出现EventBusException异常的。下面跟进findUsingInfo()方法。

SubscriberMethodFinder#findUsingInfo()

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) 
    // 从FIND_STATE_POOL数组中查找FindState,命中返回,否则直接new
    FindState findState = prepareFindState();
    // 初始化FindState
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) 
        findState.subscriberInfo = getSubscriberInfo(findState);
        // findState.subscriberInfo默认null
        if (findState.subscriberInfo != null) 
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) 
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) 
                    findState.subscriberMethods.add(subscriberMethod);
                
            
         else 
            findUsingReflectionInSingleClass(findState);
        
        // 将findState.clazz变为改类的父类
        findState.moveToSuperclass();
    
    return getMethodsAndRelease(findState);


// SubscriberMethodFinder$FindState#initForSubscriber()
void initForSubscriber(Class<?> subscriberClass) 
    this.subscriberClass = clazz = subscriberClass;
    skipSuperClasses = false;
    subscriberInfo = null;

findState.subscriberInfo默认null,那么就进入到findUsingReflectionInSingleClass(findState),先看下这个方法,等下还要返回来看。

SubscriberMethodFinder#findUsingReflectionInSingleClass()

private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;

private void findUsingReflectionInSingleClass(FindState findState) 
    Method[] methods;
    try 
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        // 获取到类中所有的方法
        methods = findState.clazz.getDeclaredMethods();
     catch (Throwable th) 
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    
    for (Method method : methods) 
        // 获取方法的修饰符
        int modifiers = method.getModifiers();
        // 必须被public修饰,而且不能为MODIFIERS_IGNORE
        // MODIFIERS_IGNORE定义为ABSTRACT、STATIC、BRIDGE、SYNTHETIC。
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) 
            // 获取方法所有参数类型
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 1) 
                // 是否有Subscribe注解标签
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) 
                    // 带有Subscribe注解标签的方法的第一个参数类型
                    Class<?> eventType = parameterTypes[0];
                    // 关联method, eventType到anyMethodByEventType
                    if (findState.checkAdd(method, eventType)) 
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        // 构造SubscriberMethod,并且添加到findState.subscriberMethods
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    
                
            // strictMethodVerification 默认为false,不会抛出异常,但还是建议符合规范
             else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) 
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);
            
         else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) 
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        
    


// `SubscriberMethodFinder#checkAdd()`
boolean checkAdd(Method method, Class<?> eventType) 
    // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
    // Usually a subscriber doesn't have methods listening to the same event type.
    Object existing = anyMethodByEventType.put(eventType, method);
    if (existing == null) 
        return true;
     else 
         ...

接下来返回SubscriberMethodFinder#findUsingInfo()接着看,在findUsingInfo()中循环执行完后return getMethodsAndRelease(findState)

static class FindState 
    final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
    ...


private List<SubscriberMethod> getMethodsAndRelease(FindState findState) 
    List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
    // 置空findState
    findState.recycle();
    synchronized (FIND_STATE_POOL) 
        for (int i = 0; i < POOL_SIZE; i++) 
            if (FIND_STATE_POOL[i] == null) 
                FIND_STATE_POOL[i] = findState;
                break;
            
        
    
    return subscriberMethods;

getMethodsAndRelease()中将findState置空,存放进FIND_STATE_POOL数组,最后返回findState.subscriberMethods。返回EventBus#register()

EventBus#register()

public void register(Object subscriber) 
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) 
        for (SubscriberMethod subscriberMethod : subscriberMethods) 
            subscribe(subscriber, subscriberMethod);
        
    

调用SubscriberMethodFinder#findSubscriberMethods()后,以List<SubscriberMethod>形式返回了订阅者所有的订阅事件。然后遍历执行subscribe()方法。看样子应该是遍历List<SubscriberMethod>,然后将订阅者和订阅事件绑定。没撒好说的,跟进subscribe()

EventBus#subscribe()

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) 
    // 获取订阅事件的类型,即订阅方法中的唯一参数类型
    Class<?> eventType = subscriberMethod.eventType;
    // 用订阅者和订阅方法构造一个Subscription对象
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    // 查找所有的订阅了订阅事件的订阅者
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    // 没有订阅者订阅过则新建个CopyOnWriteArrayList<subscriptions>,并put进subscriptionsByEventType PS:CopyOnWriteArrayList支持并发读写
    if (subscriptions == null) 
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
     else 
        // 订阅者List不为空,而且已经包含了newSubscription,则会抛出异常。即:订阅者不能重复订阅同一事件
        if (subscriptions.contains(newSubscription)) 
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        
    

    int size = subscriptions.size();
    // 根据订阅者优先级,增加到订阅者列表subscriptions的相应位置
    for (int i = 0; i <= size; i++) 
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) 
            subscriptions.add(i, newSubscription);
            break;
        
    
    // 获取订阅者所有订阅事件的列表,默认为null
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) 
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    
    // 将订阅事件添加进对应订阅者的订阅列表
    subscribedEvents.add(eventType);
    // sticky默认为false
    if (subscriberMethod.sticky) 
        if (eventInheritance) 
            // Existing sticky events of all subclasses of eventType have to be considered.
            // Note: Iterating over all events may be inefficient with lots of sticky events,
            // thus data structure should be changed to allow a more efficient lookup
            // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry<Class<?>, 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);
        
    

EventBus#Register()其实只做了三件事:

1. 查找订阅者所有的订阅事件

2. 将订阅事件作为key,所有订阅了此订阅事件的订阅者作为value存放进subscriptionsByEventType

3. 将订阅者作为key,订阅者的所有订阅事件作为value存放进typesBySubscriber

至此,EventBus.getDefault().register(this)流程完毕。

2. Post流程

EventBus#getDefault()

获取EventBus实例。和Register流程中一样,不再赘述。

EventBus#post()

/** Posts the given event to the event bus. */
public void post(Object event) 
    // 依据不同的线程获取相应的刚初始化的PostingThreadState
    PostingThreadState postingState = currentPostingThreadState.get();
    List<Object> eventQueue = postingState.eventQueue;
    // 将event加入到postingState.eventQueue
    eventQueue.add(event);
    // isPosting默认false
    if (!postingState.isPosting) 
        // 判断是否是主线程
        postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
        postingState.isPosting = true;
        if (postingState.canceled) 
            throw new EventBusException("Internal error. Abort state was not reset");
        
        try 
            // 遍历发送eventQueue中的event
            while (!eventQueue.isEmpty()) 
                postSingleEvent(eventQueue.remove(0), postingState);
            
         finally 
            postingState.isPosting = false;
            postingState.isMainThread = false;
        
    

上面代码中currentPostingThreadStateThreadLocal<PostingThreadState>对象,对ThreadLocal<>机制不了解的同学,可以查看这篇博客。下面跟进postSingleEvent()方法。

EventBus#postSingleEvent()

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error 
    // 获取event的类型
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    // eventInheritance默认为true
    if (eventInheritance) 
        // 依据订阅事件类型,将订阅事件类型及所有父类添加进eventTypes。详情见下文EventBus.lookupAllEventTypes()分析
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        // 遍历countTypes,通过调用postSingleEventForEventType()方法通知所有订阅者
        for (int h = 0; h < countTypes; h++) 
            Class<?> clazz = eventTypes.get(h);
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        
     else 
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    
    if (!subscriptionFound) 
        if (logNoSubscriberMessages) 
            Log.d(TAG, "No subscribers registered for event " + eventClass);
        
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) 
            post(new NoSubscriberEvent(this, event));
        
    

EventBus#lookupAllEventTypes()

private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) 
    synchronized (eventTypesCache) 
        // 根据订阅事件查找所有自身及父类,eventTypes默认为null
        List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
        if (eventTypes == null) 
            eventTypes = new ArrayList<>();
            Class<?> clazz = eventClass;
            while (clazz != null) 
                // 将订阅事件添加进eventTypes
                eventTypes.add(clazz);
                // 遍历订阅事件的所有父类,依次添加进eventTypes
                addInterfaces(eventTypes, clazz.getInterfaces());
                clazz = clazz.getSuperclass();
            
            // 将订阅事件和包含订阅事件自身及所有父类的eventTypes添加进eventTypesCache
            eventTypesCache.put(eventClass, eventTypes);
        
        return eventTypes;
    

现在假设传递的数据为Person类,而Person类实现了IPerson接口。通过上面的分析可以得出结论:在传递对象(Person)的时候,订阅事件中参数为被传递对象的所有父类订阅事件(IPerson)也都会被调用。笔者已经验证通过,感兴趣的同学可以再验证一下。

EventBus#postSingleEventForEventType()

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) 
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) 
        // 根据订阅事件查找所有已经注册过的订阅者
        // 注意:这里第一次传递进来的是订阅事件,之后会逐个传递进来订阅事件的父类
        subscriptions = subscriptionsByEventType.get(eventClass);
    
    if (subscriptions != null && !subscriptions.isEmpty()) 
        for (Subscription subscription : subscriptions) 
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try 
                // 参数解释:subscription-被遍历到的订阅者;event-订阅事件参数(子类);
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
             finally 
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            
            if (aborted) 
                break;
            
        
        return true;
    
    return false;

EventBus#register()最后总结道:将订阅事件作为key,所有订阅了此订阅事件的订阅者作为value存放进subscriptionsByEventType。这里就依据订阅事件然后查找对应所有的订阅者。注意:由于遍历订阅事件参数所有父类的原因,一个订阅事件的Post第一次执行postToSubscription()时,subscription参数,遍历时为订阅事件的订阅者。之后再调用postToSubscription()时,subscription参数都为订阅时间父类的订阅者。而event参数则一直是订阅事件中的唯一参数(最底层子类)。

EventBus#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 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);
    

看到这里差不多可以松口气,终于要分发调用订阅者的订阅事件了!写了整整一下午,容我抽支烟再。

首先根据ThreadMode确定分发类型。这里以最常用的Main为例,其余两个Poster同理。如果是isMainThread=true,那么直接调用invokeSubscriber(),否则调用mainThreadPoster.enqueue()。下面分别解释这两种情况。

EventBus#invokeSubscriber()

void invokeSubscriber(Subscription subscription, Object event) 
    try 
        // 反射调用
        subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
     catch (InvocationTargetException e) 
        handleSubscriberException(subscription, event, e.getCause());
     catch (IllegalAccessException e) 
        throw new IllegalStateException("Unexpected exception", e);
    

没撒好说的,直接反射调用订阅者的订阅事件。注意:参数event是子类对象,就算调用订阅事件中唯一参数是参数的父类,那么传递的仍然是子类对象。笔者已经验证,感兴趣的同学可以自行验证。然后查看HandlerPoster#enqueue()

HandlerPoster#enqueue()

final class HandlerPoster extends Handler 

    ...

    void enqueue(Subscription subscription, Object event) 
        // 尝试从pendingPostPool中获取pendingPost,没有则直接new PendingPost
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) 
            // 加入队列
            queue.enqueue(pendingPost);
            if (!handlerActive) 
                handlerActive = true;
                // 发送空消息 调用handleMessage
                if (!sendMessage(obtainMessage())) 
                    throw new EventBusException("Could not send handler message");
                
            
        
    

    @Override
    public void handleMessage(Message msg) 
        // 已经切换到主线程 
        while (true) 
            // 遍历获取queue中的PendingPost对象
           PendingPost pendingPost = queue.poll();
            ...
            // 调用eventBus.invokeSubscriber
            eventBus.invokeSubscriber(pendingPost);
            ...
        
    

EventBus#invokeSubscriber()

void invokeSubscriber(PendingPost pendingPost) 
    // 提取订阅事件
    Object event = pendingPost.event;
    // 提取订阅者
    Subscription subscription = pendingPost.subscription;
    // 释放pendingPost
    PendingPost.releasePendingPost(pendingPost);
    if (subscription.active) 
        // 反射调用订阅者的订阅事件
        invokeSubscriber(subscription, event);
    

至此,订阅者在相应线程调用订阅事件完成,EventBus.getDefault().Post()流程完毕。

EventBus#Post()也只做了三件事

1. 根据订阅事件在subscriptionsByEventType中查找相应的订阅者

2. 分发订阅者的订阅事件调用线程

2. 通过反射调用订阅者的订阅事件

3. unregister流程

EventBus#getDefault()

获取EventBus实例。和Register流程中一样,不再赘述。

EventBus#unregister()

public synchronized void unregister(Object subscriber) 
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) 
        for (Class<?> eventType : subscribedTypes) 
            unsubscribeByEventType(subscriber, eventType);
        
        typesBySubscriber.remove(subscriber);
     else 
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    

EventBus#unsubscribeByEventType()

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) 
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) 
        int size = subscriptions.size();
        for (int i = 0; i < size; i++) 
            Subscription subscription = subscriptions.get(i);
            if (subscription.subscriber == subscriber) 
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            
        
    

EventBus#register()最后总结道:

将订阅事件作为key,所有订阅了此订阅事件的订阅者作为value存放进subscriptionsByEventType

将订阅者作为key,订阅者的所有订阅事件作为value存放进typesBySubscriber

现在要反注册咯。移除相应的keyvalue即可。EventBus3.0的使用及源码解析到此结束,Have a nice day~

以上是关于Android EventBus3.0使用及源码解析的主要内容,如果未能解决你的问题,请参考以下文章

EventBus3.0源码分析

EventBus3.0源码分析

EventBus3.0源码分析

EventBus3.0源码浅析与理解

EventBus3.0源码浅析与理解

EventBus3.0源码解读