EventBus3.0源码分析

项目地址:
https://github.com/greenrobot/EventBus

EventBus是我们在项目当中最常用的开源框架之一。对于EventBus的使用方法也是非常的简单。然而EventBus内部的实现原理也不是很复杂。在这里便针对EventBus3.0的源码进行一下详细的分析

一、使用

1.1 在gradle中添加

// 3.0版本
compile 'org.greenrobot:eventbus:3.0.0'
// 2.4版本
compile 'de.greenrobot:eventbus:2.4.0'

1.2 定义事件

public class MessageEvent { /* Additional fields if needed */ }

1.3 注册订阅者

2.4版本中有四种注册方法,区分了普通注册和粘性事件注册,并且在注册时可以选择接收事件的优先级,
3.0版本将粘性事件以及订阅事件的优先级换了一种更好的实现方式,所以3.0版本中的注册就变得简单,只有一个register()方法即可.

// 3.0 版本
EventBus.getDefault().register(this);
//2.4版本的注册
EventBus.getDefault().register(this);
EventBus.getDefault().register(this, 100);
EventBus.getDefault().registerSticky(this, 100);
EventBus.getDefault().registerSticky(this);

1.4 响应事件订阅方法

在2.4版本中只有通过onEvent开头的方法会被注册,而且响应事件方法触发的线程通过onEventMainThread或onEventBackgroundThread这些方法名区分,而在3.0版本中.通过@Subscribe注解,来确定运行的线程threadMode,是否接受粘性事件sticky以及事件优先级priority,而且方法名不在需要onEvent开头,所以又简洁灵活了不少.

//3.0版本
@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true, priority = 100)
public void test(String str) {

}

//2.4版本
public void onEvent(String str) {

}
public void onEventMainThread(String str) {

}
public void onEventBackgroundThread(String str) {

}

1.5 发送事件

我们可以通过EventBus的post()方法来发送事件,发送之后就会执行注册过这个事件的对应类的方法.或者通过postSticky()来发送一个粘性事件.在代码是2.4版本和3.0版本是一样的.

EventBus.getDefault().post("zzx");
EventBus.getDefault().postSticky("zzx");

1.6 解除注册

当我们不在需要接收事件的时候需要解除注册unregister,2.4和3.0的解除注册也是相同的.代码如下:

EventBus.getDefault().unregister(this);

二、源码分析

看Eventbus几行代码就搞定了事件的订阅与接收,内部原理是怎么实现的呢,让我们一起去分析

2.1 我们使用是直接EventBus.getDefault(), 先看一下EventBus实例怎么来的

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

这里就是设计模式里我们常用的单例模式了,目的是为了保证getDefault()得到的都是同一个实例。如果不存在实例,就调用了EventBus的构造方法

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

    public EventBus() {
        this(DEFAULT_BUILDER);
    }

    EventBus(EventBusBuilder builder) {
        //key:订阅的事件,value:订阅这个事件的所有订阅者集合
        //private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        subscriptionsByEventType = new HashMap<>();
        //key:订阅者对象,value:这个订阅者订阅的事件集合
        //private final Map<Object, List<Class<?>>> typesBySubscriber;
        typesBySubscriber = new HashMap<>();
        //粘性事件 key:粘性事件的class对象, value:事件对象
        //private final Map<Class<?>, Object> stickyEvents;
        stickyEvents = new ConcurrentHashMap<>();
        //事件主线程处理
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        //事件 Background 处理
        backgroundPoster = new BackgroundPoster(this);
        //事件异步线程处理
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        //订阅者响应函数信息存储和查找类
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        //是否支持事件继承
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }

可以看出是通过初始化了一个EventBusBuilder()对象来分别初始化EventBus的一些配置,当我们在写一个需要自定义配置的框架的时候,这种实现方法非常普遍,将配置解耦出去,使我们的代码结构更清晰.注释里我标注了大部分比较重要的对象,这里没必要记住,看下面的文章时如果对某个对象不了解,可以再回来看看.

2.2 register()

3.0的注册只提供一个register()方法了,所以我们先来看看register()方法做了什么

  public void register(Object subscriber) {
        // 首先获得订阅者的class对象
        Class<?> subscriberClass = subscriber.getClass();

        // 通过subscriberMethodFinder来找到订阅者订阅了哪些事件.返回一个SubscriberMethod对象的List,SubscriberMethod
        // 里包含了这个方法的Method对象,以及将来响应订阅是在哪个线程的ThreadMode,以及订阅的事件类型eventType,以及订阅的优
        // 先级priority,以及是否接收粘性sticky事件的boolean值.
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                //订阅
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

在这里可以看到register这个方法中的代码很简短,但是在它的内容却一点也不简单。对于register中的参数,就是我们的订阅者,也就是我们经常传入的this对象。在这个方法中主要完成了两件事情。首先通过findSubscriberMethods方法来查找订阅者中所有的订阅方法。然后遍历订阅者的订阅方法来完成订阅者的订阅操作。下面来详细的分析这两步的实现过程。

2.2.1 订阅方法的查找过程 findSubscriberMethods 方法实现

首先在这里来看一下findSubscriberMethods这个方法是如何查找订阅者的订阅方法。在这先描述一下SubscriberMethod类。对于SubscriberMethod类中,主要就是用保存订阅方法的Method对象,线程模式,事件类型,优先级,是否粘性事件等属性。下面就来看一下findSubscriberMethods方法。

 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
 //从缓存中获取SubscriberMethod集合
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
//ignoreGeneratedIndex是否忽略注解器生成的MyEventBusIndex 3.0才有的
// ignoreGeneratedIndex 默认是false
        if (ignoreGeneratedIndex) {
         //通过反射获取subscriberMethods
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
        //通过注解器生成的MyEventBusIndex信息获取subscriberMethods,
        //如果没有配置MyEventBusIndex,依然通过通过反射获取subscriberMethods
            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;
        }
    }

在这个方法里面的逻辑依然也是十分的清晰。首先会从缓存中查找是否有订阅方法的集合,若是存在则直接返回缓存中的该订阅者的订阅方发集合。若是不存在,便从订阅者中找出全部的订阅方法。对于ignoreGeneratedIndex属性表示是否忽略注解器生成的MyEventBusIndex(在项目重新rebuild以后,会自动生成在build文件夹下,类名也可以自己定义)。如何生成MyEventBusIndex类以及他的使用,可以参考官方文档ignoreGeneratedIndex的默认值为false,可以通过EventBusBuilder来设置它的值。在这里会根具ignoreGeneratedIndex的值来采用不同的方式获取订阅方法的集合subscriberMethods。在获得subscriberMethods以后,如果订阅者中不存在@Subscribe注解且为public的订阅方法,则会抛出异常。这也就是说对于订阅者若是要成功注册到EventBus中,在订阅者中必须存在通过@Subscribe注解且为public类型的订阅方法。在成功获取到订阅方法集合以后,便将订阅方法集合添加到缓存中。对于这个缓存它是以订阅者的类作为key,订阅方法集合作为value的Map类型。

由于在我们的项目中经常通过EventBus单例模式来获取默认的EventBus对象。所以就针对ignoreGeneratedIndex为false的情况下看一下EventBus是如何获得订阅方法集合的。在这里调用了findUsingInfo方法。下面就来看一下findUsingInfo这个方法

 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
 //创建和初始化FindState对象
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
        //获取订阅者信息,没有配置MyEventBusIndex返回null
            findState.subscriberInfo = getSubscriberInfo(findState);
            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.moveToSuperclass();
        }
        //回收处理findState,并返回订阅方法的List集合
        return getMethodsAndRelease(findState);
    }

下面就来看一下如何通过反射来查找订阅方法,也就是看一下findUsingReflectionInSingleClass的执行过程。

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();
        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) {
                    //保存到findState对象当中
                    Class<?> eventType = parameterTypes[0];
                    if (findState.checkAdd(method, eventType)) {
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    }
                }
            } 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");
        }
    }
}

这段代码的执行过程其实并不是很复杂。在这里主要是使用了Java的反射和对注解的解析。首先通过反射来获取订阅者中所有的方法。并根据方法的类型,参数和注解来找到订阅方法。找到订阅方法后将订阅方法相关信息保存到FindState当中。到这里便完成对订阅者中所有订阅方法的查找
接下来继续回到register方法中,看subscribe方法实现

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    //获取订阅方法中的订阅事件
    Class<?> eventType = subscriberMethod.eventType;
    //创建一个Subscription来保存订阅者和订阅方法
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //获取当前订阅事件中Subscription的List集合
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
    //该事件对应的Subscription的List集合不存在,则重新创建并保存在subscriptionsByEventType中
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        //判断是订阅者是否已经被注册
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }

    //将newSubscription按照订阅方法的优先级插入到subscriptions中
    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    //通过订阅者获取该订阅者所订阅事件的集合
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    //将当前的订阅事件添加到subscribedEvents中
    subscribedEvents.add(eventType);
    //粘性事件的处理,在这里不做详细分析
    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);
        }
    }
}

在这个方法中便是订阅者真正的注册过程。首先会根据subscriber和subscriberMethod来创建一个Subscription对象。之后根据事件类型获取或创建一个Subscription集合subscriptions并添加到typesBySubscriber对象中。最后将刚才创建的Subscription对象添加到subscriptions之中。到此注册过程就完成了

你只要记得一件事:扫描了所有的方法,把匹配的方法最终保存在subscriptionsByEventType(Map,key:eventType ; value:CopyOnWriteArrayList )中;
eventType是我们方法参数的Class,Subscription中则保存着subscriber, subscriberMethod(method, threadMode, eventType), priority;包含了执行改方法所需的一切.

2.3 事件的发送 post 实现

现在来看一下事件的整个发送过程。在获取到EventBus对象以后,通过post方法来进行对事件的提交,下面就来看一下整个post方法是如何对事件进行提交的。

public void post(Object event) {
    //PostingThreadState保存着事件队列和线程状态信息
    PostingThreadState postingState = currentPostingThreadState.get();
    //获取事件队列,并将当前事插入到事件队列中
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);

    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 {
            //处理队列中的所有事件
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

首先是通过currentPostingThreadState.get()方法来得到当前线程PostingThreadState的对象,为什么是说当前线程我们来看看currentPostingThreadState的实现:

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

    final static class PostingThreadState {
    //通过post方法参数传入的事件集合
    final List<Object> eventQueue = new ArrayList<Object>(); 
    boolean isPosting; //是否正在执行postSingleEvent()方法
    boolean isMainThread;
    Subscription subscription;
    Object event;
    boolean canceled;
    }

currentPostingThreadState的实现是一个包含了PostingThreadState的ThreadLocal对象,关于ThreadLocal
==ThreadLocal== 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,而这段数据是不会与其他线程共享的。其内部原理是通过生成一个它包裹的泛型对象的数组,在不同的线程会有不同的数组索引值,通过这样就可以做到每个线程通过 get() 方法获取的时候,取到的只能是自己线程所对应的数据。
在 EventBus 中, ThreadLocal 所包裹的是一个 PostingThreadState 类,它仅仅是封装了一些事件发送中过程所需的数据。

回到 post() 方法,我们看到其核心代码是这句:

while (!eventQueue.isEmpty()) {
    postSingleEvent(eventQueue.remove(0), postingState);
}

每次调用post()的时候都会传入一个事件,这个事件会被加入到队列。而每次执行postSingleEvent()都会从队列中取出一个事件,这样不停循环取出事件处理,直到队列全部取完。
再看 postSingleEvent() 方法

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        //是否触发订阅了该事件(eventClass)的父类,以及接口的类的响应方法.
        if (eventInheritance) {
            //查找eventClass类所有的父类以及接口
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            //循环postSingleEventForEventType
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                //只要右边有一个为true,subscriptionFound就为true
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            //post单个
            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) {
                //发送一个NoSubscriberEvent事件,如果我们需要处理这种状态,接收这个事件就可以了
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

跟着上面的代码的注释,我们可以很清楚的发现是在postSingleEventForEventType()方法里去进行事件的分发,代码如下:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        //获取订阅了这个事件的Subscription列表.
        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 {
                    //分发给订阅者
                    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;
    }

    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);
        }
    }

总结上面的代码就是,首先从subscriptionsByEventType里获得所有订阅了这个事件的Subscription列表,然后在通过postToSubscription()方法来分发
事件,在postToSubscription()通过不同的threadMode在不同的线程里invoke()订阅者的方法,ThreadMode共有四类:

1、PostThread:默认的 ThreadMode,表示在执行 Post 操作的线程直接调用订阅者的事件响应方法,不论该线程是否为主线程(UI 线程)。当该线程为主线程时,响应方法中不能有耗时操作,否则有卡主线程的风险。适用场景:对于是否在主线程执行无要求,但若 Post 线程为主线程,不能耗时的操作;

2、MainThread:在主线程中执行响应方法。如果发布线程就是主线程,则直接调用订阅者的事件响应方法,否则通过主线程的 Handler 发送消息在主线程中处理——调用订阅者的事件响应函数。显然,MainThread类的方法也不能有耗时操作,以避免卡主线程。适用场景:必须在主线程执行的操作;

3、BackgroundThread:在后台线程中执行响应方法。如果发布线程不是主线程,则直接调用订阅者的事件响应函数,否则启动唯一的后台线程去处理。由于后台线程是唯一的,当事件超过一个的时候,它们会被放在队列中依次执行,因此该类响应方法虽然没有PostThread类和MainThread类方法对性能敏感,但最好不要有重度耗时的操作或太频繁的轻度耗时操作,以造成其他操作等待。适用场景:操作轻微耗时且不会过于频繁,即一般的耗时操作都可以放在这里;

4、Async:不论发布线程是否为主线程,都使用一个空闲线程来处理。和BackgroundThread不同的是,Async类的所有线程是相互独立的,因此不会出现卡线程的问题。适用场景:长耗时操作,例如网络访问

这里我们只来看看UI线程中invokeSubscriber(subscription, event);是如何实现的,

 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对象作为参数传入.至此post()流程就结束了

2.4 unregister() 方法

public synchronized void unregister(Object subscriber) {
        //通过typesBySubscriber来取出这个subscriber订阅者订阅的事件类型,
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            //分别解除每个订阅了的事件类型
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            //从typesBySubscriber移除subscriber
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

然后接着看unsubscribeByEventType()方法的实现:

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        //subscriptionsByEventType里拿出这个事件类型的订阅者列表.
        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--;
                }
            }
        }
    }

最终分别从typesBySubscriber和subscriptions里分别移除订阅者以及相关信息即可.

在2.4版本里EventBus写出的代码可读性不是太好因为所有订阅方法都是onEvent开头,这样就使代码的可读性降低不少,但是3.0之后我们就不用担心这些了,因为
方法名已经不再需要onEvent开头了。所以总体上来说EventBus还是值得我们在项目中使用的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值