频道栏目
首页 > 资讯 > Android > 正文

Android EventBus3.0使用及源码解析

16-07-11        来源:[db:作者]  
收藏   我要投稿

叨了个叨

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

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

EventBus3.0简介

EventBus是greenrobot出品的一个用于Android中事件发布/订阅的库。以前传递对象可能通过接口、广播、文件等等,尤其像同一个Activity两个Fragment之间采用接口传递对象,十分的麻烦,而且耦合度较高。使用EventBus之后,这些将不再是问题。盗用GiHub上EventBus的一张图。
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等等都是可以的,这里为了方便演示直接传递了String。Log信息如下:
main

child
第一张图中发布者发送线程为主线程,即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 ThreadMode}s! */
    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 subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

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

SubscriberMethodFinder#findSubscriberMethods()

List findSubscriberMethods(Class subscriberClass) {
    // 查找缓存
    List 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 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 subscriberMethods = new ArrayList<>();
    ...
}

private List getMethodsAndRelease(FindState findState) {
    List 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 subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

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

EventBus#subscribe()

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    // 获取订阅事件的类型,即订阅方法中的唯一参数类型
    Class eventType = subscriberMethod.eventType;
    // 用订阅者和订阅方法构造一个Subscription对象
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    // 查找所有的订阅了订阅事件的订阅者
    CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
    // 没有订阅者订阅过则新建个CopyOnWriteArrayList,并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<>> 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).
            Set<><>, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry<>, 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 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对象,对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<>> 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<>> lookupAllEventTypes(Class eventClass) {
    synchronized (eventTypesCache) {
        // 根据订阅事件查找所有自身及父类,eventTypes默认为null
        List<>> 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 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<>> 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 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~

相关TAG标签
上一篇:Toast 自定义布局 完成图片上传提示
下一篇:iOS开发——响应链(Responder Chain)的深入理解和代码示例(二)
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站