EventBus源码分析

简介

EventBus 是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent, Handler, BroadCast 在 Fragment,Activity,Service,线程之间传递消息.优点是开销小,使用方便,可以很大程度上降低它们之间的耦合,使得我们的代码更加简洁,耦合性更低,提升我们的代码质量。


概念

  • 事件
    也被称为消息,其实就是一个对象,可以是网络请求返回的一个字符串。事件分为:一般事件和粘性事件,粘性事件简单来说就是在发送事件之后再订阅该事件也能收到该类型事件最近的一个粘性事件。而一般事件如果在事件发送之后再订阅该事件,是无法接收到这次事件的。
  • 发布者
    发布某事件的对象,通过 post 接口发布事件。
  • 订阅者
    订阅某种事件类型的对象,当有发布者发布这类事件后,EventBus会执行订阅者的onEvent函数,这个函数也被称为事件响应函数,订阅者通过 register 接口订阅某个事件类型,unregister 接口退订。订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为 0。

基本使用

EventBus 2.x的使用

(1)将需要订阅事件的类通过EventBus类进行注册()

EventBus.getDefault().register(this);
EventBus.getDefault().register(this, 100);  //设置了优先级
EventBus.getDefault().registerSticky(this, 100);   //给粘性事件设置了优先级
EventBus.getDefault().registerSticky(this);

(2)定义事件

class UserDataEvent(val isSuccessful :Boolean) {}  
//参数可以是传递的消息,也可以是一种消息的传递状态,这里定义的是数据是否加载成功

(3)发送事件

EventBus.getDefault().post("str");  //发送一般事件
EventBus.getDefault().postSticky("str");  //发送粘性事件

(4)编写响应事件的方法

public void onEvent(String str) {

}
public void onEventMainThread(String str) {

}
public void onEventBackgroundThread(String str) {

}

(5)将需要订阅事件的类通过EventBus类进行解除注册

EventBus.getDefault().unregister(this);

EventBus 3.x的使用

(1)将需要订阅事件的类通过EventBus类进行注册,这一步和2.0不同,注册方式只有一种

EventBus.getDefault().register(this);

(2)这个和2.x比没有什么变化,就还是简单的定义事件就可以了
(3)和2.x一样,同样是上面发送事件的两种方式
(4)事件响应和以前有所不同

//3.0版本  将运行的线程、是否接受粘性事件以及事件的优先级定义在注解中
//这种方式使得函数名更加的灵活
@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true, priority = 100)
public void test(String str) {
}

(5)解除注册的过程也和2.x相同


源码分析

查找订阅信息

注册的时候使用的EventBus.getDefault().register(this),首先分析一下getDefault()的实现过程

public class EventBus {
    /** Log tag, apps may override it. */
    public static String TAG = "EventBus";
    static volatile EventBus defaultInstance;
	public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }

其实很简单,就是创建了EventBus的一个单例
使用构造方法创建了EventBus实例,构造方法中发生了什么?

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
public EventBus() {
        this(DEFAULT_BUILDER);
    }

    EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadSupport = builder.getMainThreadSupport();
        //前台发送者
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        //后台发送者
        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的配置

EventBusBuilder

public class EventBusBuilder {
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    boolean logSubscriberExceptions = true;   //监听异常日志
    boolean logNoSubscriberMessages = true;   //没有订阅者的话,显示一个log提示
    boolean sendSubscriberExceptionEvent = true; //发送监听到的异常事件
    boolean sendNoSubscriberEvent = true; //没有订阅者,发送一条默认事件
    boolean throwSubscriberException; 
    boolean eventInheritance = true;  //event的子类是否可以影响到订阅者
    boolean ignoreGeneratedIndex;
    boolean strictMethodVerification;
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
    List<Class<?>> skipMethodVerificationForClasses;
    List<SubscriberInfoIndex> subscriberInfoIndexes;
    Logger logger;
    MainThreadSupport mainThreadSupport;
public void register(Object subscriber) {
	//记录注册类
    Class<?> subscriberClass = subscriber.getClass();
    //找到注册类中的带有Subscribe注解的方法,也就是找到全部的订阅事件
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
   synchronized (this) {
      for (SubscriberMethod subscriberMethod : subscriberMethods) {
      //遍历这些方法,进行订阅过程。
        subscribe(subscriber, subscriberMethod);
      }
  }
    }

首先看一下是如何找到全部的订阅事件的,主要是通过subscriberMethodFinder.findSubscriberMethods(subscriberClass)来进行查找到的

private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();

 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
 //先在本地的缓存中进行查找,如果能找到,代表原来这个类注册过,直接使用信息就可以
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        //是否忽略注解器生成的MyEventBusIndex类,可以通过EventBusBuilder的ignoreGeneratedIndex方法进行设置
        if (ignoreGeneratedIndex) {
        //利用反射来读取订阅类中的订阅方法信息
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
        //从注解器生成的MyEventBusIndex类中获得订阅类的订阅方法信息
            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缓存
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }
查找全部订阅方法过程总结

在这里插入图片描述
METHOD_CACHE是Map类型,Key值为订阅类,Value值为订阅类中的所有订阅方法,其中的判断条件ignoreGeneratedIndex是由EventBusbuilder中的ignoreGeneratedIndex()方法来进行设置的,通常默认情况是false,也就是默认使用注解处理器进行处理。

通过反射来获取订阅类中的订阅方法的信息
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

首先就看到FindState,看一下prepareFindState

private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();
    }

从池中拿出一个FindState对象,FindState中维护的就是我们对订阅方法查找结果的封装。第二步,initForSubscriber()就是将我们的订阅者传给FindState对象。第三步做的就是不断从订阅者和订阅者的父类去查找订阅方法,一起看findUsingReflectionInSingleClass()。

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // 这比getMethods更快
            //返回class对象所表示的类中的所有方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            try {
                methods = findState.clazz.getMethods();
            } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
                String msg = "Could not inspect methods of " + findState.clazz.getName();
                if (ignoreGeneratedIndex) {
                    msg += ". Please consider using EventBus annotation processor to avoid reflection.";
                } else {
                    msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
                }
                throw new EventBusException(msg, error);
            }
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers(); //获得方法的修饰符
            //判断修饰符是public 并且修饰符不能是abstract、static、volatile、synthetic
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes(); //返回参数类型的数组
                if (parameterTypes.length == 1) { //订阅者方法只能有一个参数
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);//返回Subscribe注释类型的注释
                    if (subscribeAnnotation != null) {
                        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");
            }
        }
    }

经过对修饰符类型、参数个数以及注解类型的限制,找到订阅者方法。但是还是会经过checkadd判断,这个判断做了什么呢?

boolean checkAdd(Method method, Class<?> eventType) {
            //2级检查:第一级仅限事件类型(fast),第二级需完整签名。
            //通常订阅者没有监听相同事件类型的方法
            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) {//HashMap中没有存储过相同事件的方法
                return true; 
            } else {
                if (existing instanceof Method) {
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    // 放任何非Method对象“消费”现有方法
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }

二级检查的过程

private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());

            String methodKey = methodKeyBuilder.toString();
            Class<?> methodClass = method.getDeclaringClass();
            Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
            //如果methodClassOld是methodClass的父类或者methodClassOld为空
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                return true;
            } else {
                //否则,保存我们的签名的MethodClass
                subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            }
        }

将方法名和事件类型当作key,来保存方法,如果我们之前保存的方法的value是父类,则更新为子类,并返回true,因为子类会继承父类中的方法,如果我们之前保存的value是子类,则不进行更新(用旧的value覆盖新的value值),始终是保存子类的方法,因为子类最终都会继承父类的方法。

经过checkadd判断后,然后就将此类中找到的订阅者的方法,添加到FindState对象的subscriberMethod集合中,然后遍历父类,循环这个过程。最后返回getMethodsAndRelease(findState)

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        findState.recycle(); //将findState进行回收
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;//放在FindState中以便复用
                    break;
                }
            }
        }
        return subscriberMethods;//返回一个订阅者方法的集合
    }

到此,通过反射的方式解析注解,找到订阅方法的方式分析完成!再看一下第二种,通过注解处理器(apt),针对源码的处理,是在执行编译的过程中的,性能比反射好得多。

利用反射获取订阅方法总结

在这里插入图片描述

FIND_STATE_POOL是findState的复用池,而FindState的属性如下,通过循环查找订阅类及其父类的订阅方法,并返回。

FindState
 static class FindState {
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();   // 所有的订阅方法
        final Map<Class, Object> anyMethodByEventType = new HashMap<>(); //key为事件类型,value值为对应事件的订阅方法
        //key:订阅方法名>事件类型名,value:订阅方法
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;  //订阅
        Class<?> clazz;
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;
通过注解处理器来获取订阅类中的订阅方法的信息
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();  //和上面方式相同,prepareFindState从池中获取FindState
        findState.initForSubscriber(subscriberClass);//把订阅类传给FindState对象
        while (findState.clazz != null) {
        //从EventBusIndex中查找订阅信息,并保存在findState.subscriberInfo中,以便下次直接在缓存中查找
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
            //将查找到的订阅方法信息添加到findState.subscriberMethods中
                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
        return getMethodsAndRelease(findState);
    }

具体分析一下从EventBusIndex中查找订阅信息的过程

 private SubscriberInfo getSubscriberInfo(FindState findState) {
 		//查找缓存是否存在订阅信息,有则直接返回
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        //从我们传入的MyEventBusIndex中查找是否存在订阅信息,订阅信息就是订阅方法,包括父类的订阅方法
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            //看一下这里是不是将数据保存在缓存中
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

看一下subscriberInfoIndexes的来源,来源于EventBusBuilder对象,具体分析一下:
引入EventBusAnnotationProcessor库之后,配置项目的build.gradle文件就会看到EventBus的注解处理器生成的类:MyEventBusIndex

/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
    
    // 类初始化时直接赋值
    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
 
        // 直接new一个SimpleSubscriberInfo并加入SUBSCRIBER_INDEX
        putIndex(new SimpleSubscriberInfo(com.example.myapp.MainActivity.Companion.class,
                true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("handleEvent", com.example.myapp.MyEvent.class,
                    ThreadMode.MAIN),
        }));
 
    }
 
    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }
 
    /**
    * 根据类查找缓存
    **/
    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

将订阅类和订阅方法全部存放在了Map中,最后在EventBus初始化的时候,将这个类传进去就可以了

   EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus().register(this);

而在EventBusBuilder的addIndex方法向subscriberInfoIndexes添加了数据

public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

这样就通过apt方式来处理了注解,这里的订阅信息是在编译过程中找到的,不会在运行期做任何的事情,所以效率很高。

订阅

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
   Class<?> eventType = subscriberMethod.eventType;   //得到事件类型
   Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //根据订阅者和订阅方法构造一个订阅事件
   //subscriptionsByEventType 相当于一个缓存,是根据eventType去查找Subsciption的集合
   CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
   //如果缓存中没有,则新建
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
        //如果集合中含有相同的Subscription,则抛出异常
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
        /*如果集合中没有元素,比如说上面新建的情况,就添加新的Subscription
       如果集合中有元素,或者subscriberMethod.priority比集合中的元素低,集合是按优先级由高到低排列的
      将新的Subscription按要求添加在相应位置就可以了*/
        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;
            }
        }
        //typesBySubscriber是根据订阅者去查找EventType的缓存,为了是unregister(this),根据this,去解绑事件的。
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
        //如果是粘性事件
        if (subscriberMethod.sticky) {
        //Event的子类可以影响到订阅者时
            if (eventInheritance) {
     			//必须考虑eventType的所有子类的现有粘性事件。
				//注意:对所有事件进行迭代可能效率低下,因为有很多粘性事件,
				//因此,应该更改数据结构以允许更有效的查找
				//(例如,存储超类的子类的附加映射:Class->List<Class>)。
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) { //遍历所有的粘性事件
                    Class<?> candidateEventType = entry.getKey();
                    //当前事件是粘性事件的父类,则将粘性事件也要发送给当前的newSubscription
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else { //Event的子类不能影响到订阅者时,则只将此次事件进行发送
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

里面就做了两件事,将我们的订阅方法和订阅者,封装到subscriptionsByEventType和typesBySubscriber,至于这两个对象是干什么的呢?第一个是我们投递订阅事件的时候,就是根据我们的EventType找到我们的订阅事件,从而去分发事件,处理事件的;第二个是在调用unregister(this)的时候,根据订阅者找到我们的EventType,又根据我们的EventType找到订阅事件,从而解绑用的,具体分析在解注册分析中,第二件事,就是如果是粘性事件的话,就立马投递、执行。

粘性事件

具体分析一下粘性事件的投递、执行过程

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        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, isMainThread());
        }
    }

和普通事件的发送过程一样,最终也是调用了postToSubscription进行发送。
一直是使用stickyEvents中的EventType数据,当调用postSticky()就会将粘性事件添加到stickyEvents中

public void postSticky(Object event) {
        synchronized (stickyEvents) {
            stickyEvents.put(event.getClass(), event);
        }
// Should be posted after it is putted, in case the subscriber wants to remove immediately
        post(event);
    }

将粘性事件添加到stickyEvents之后,才会进行发布的流程。

到此注册过程分析完成!

发布

普通事件的发送只需要用post,粘性事件发送使用postSticky

public void post(Object event) {
		//线程中的投递状态
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            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;
            }
        }
    }

循环投递过程调用了postSingleEvent

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            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) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

最终还是会走到postSingleEventForEventType

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
        //得到这种事件类型对应的全部的subscription
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {//将postingState进行回收
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

继续看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 MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(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);
        }
    }

暂时分析一种情况:当线程模式是主线程时,意味着,我们需要执行的代码在主线程中操作。
如果是主线程,就是通过invokeSubscriber()利用反射,直接运行订阅的方法
如果不是主线程,我们需要mainThreadPoster将我们的订阅事件入队列,看看mainThreadPoster的工作原理:

mainThreadPoster是通过mainThreadSupport.createPoster来创建的,调用的代码如下:
public Poster createPoster(EventBus eventBus) { return new HandlerPoster(eventBus, looper, 10);
返回的是HandlerPoster对象

public class HandlerPoster extends Handler implements Poster {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;  //10
        queue = new PendingPostQueue();
    }
    //调用的这个方法
    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
        //入队列
            queue.enqueue(pendingPost);
            //如果此时 handleMessage() 没有在运行中,则发送一条空消息让 handleMessage 响应 
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                //如果在一定时间内仍然没有发完队列中所有的待发送者,则退出
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

在EventBus初始化的时候,mainThreadPoster就已经获取主线程的Looper了,就是用到了我们Android的消息处理机制,Looper,Handler。至于消息队列是自己维护的一个单向的链表。如果handleMessage没有在运行中,向Andorid的主线程Looper投递一个空消息,然后在HandlerMessage()方法里面从自己维护的队列中取出PendingPost 进行处理。

final class PendingPost {
//复用池
    private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();

    Object event;
    Subscription subscription;
    PendingPost next;

调用了invokeSubscriber

void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        //如果没有解注册
        if (subscription.active) {
        //invokeSubscriber()利用反射,直接运行订阅的方法
            invokeSubscriber(subscription, event);
        }
    }

解除注册

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 {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

在typesBySubscriber移除了,调用了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中typesBySubscriber这个属性,通过订阅者去查找订阅事件,然后去一一解绑


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值