EventBus源码分析

基本使用

引入

​ 在模块gradle脚本中引入EventBus

implementation 'org.greenrobot:eventbus:3.2.0'
定义事件
public static class MessageEvent { /* Additional fields if needed */ }
订阅事件

​ 通过Subscribe订阅事件.注解中包含许多参数,如线程环境,事件优先级,以及是否为粘性事件.

/**
* 订阅事件
* 运行在UI线程中
* 优先级为1
* 非粘性事件
*/
@Subscribe(threadMode = ThreadMode.MAIN,priority=1,sticky=false)  
public void onMessageEvent(MessageEvent event) {/* Do something */};
注册与反注册

​ 在需要观察事件的组建中注册,同时在组建销毁时候进行反注册

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
发送事件
EventBus.getDefault().post(new MessageEvent());

源码分析

EventBus实例

EventBus通过静态方法EventBus.getDefault()获取实例.

   // 单例模式
	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;
    }

​ 看其构造方法,它采用了构造器模式,并且内部存在一个静态的构造器builder

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

​ 查看其构造器

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

    boolean logSubscriberExceptions = true;
    boolean logNoSubscriberMessages = true;
    boolean sendSubscriberExceptionEvent = true;
    boolean sendNoSubscriberEvent = true;
    boolean throwSubscriberException;
    // 发布的事件是否支持继承,即当发布子事件时候,其订阅其父类的订阅者也会收到通知
    boolean eventInheritance = true;
    // 是否强制使用反射
    boolean ignoreGeneratedIndex;
    // 严格的方法验证
    boolean strictMethodVerification;
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
    List<Class<?>> skipMethodVerificationForClasses;
    List<SubscriberInfoIndex> subscriberInfoIndexes;
    Logger logger;
    MainThreadSupport mainThreadSupport;

    EventBusBuilder() {
    }
}

EventBusBuilder中的几个属性必须值得注意

  1. eventInheritance定义的事件是否支持继承(多层次模式).该参数默认是支持的.支持则意味着当发布子事件时候,其父事件的订阅者也会接到通知.但是,这回影响到事件发布越接收的速度.
  2. ignoreGeneratedIndex3.0的版本后,EventBus加入了编译时注解解析器去解析订阅的方法响应,以替代运行时注解从而提高运行效率.该参数代表是否强制使用运行时反射.
  3. strictMethodVerification严格的方法验证.

以上三点非常重要

订阅方法的解析

EventBus方法的注册方法如下

    public void register(Object subscriber) {
        // 注册者的类型
        Class<?> subscriberClass = subscriber.getClass();
        // 订阅方法的解析
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                // 订阅
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

register方法传入的方法参数为Object.获取该对象的type,然后通过SubscriberMethodFinder类的findSubscriberMethods获取所有的订阅方法.订阅方法的抽象类为SubscriberMethod.遵循单一性原则,SubscriberMethodFinder的唯一功能就是解析订阅信息.

public class SubscriberMethod {
    // 方法
    final Method method;
    // 线程模型
    final ThreadMode threadMode;
    // 事件类型,
    final Class<?> eventType;
    // 优先级
    final int priority;
    // 是否是粘性事件
    final boolean sticky;
    // 可以唯一标识这个对象
    String methodString; 
}

​ 需要注意的是findSubscriberMethods返回的是List对象,说明一个组建中可以订阅多种类型的事件.查看订阅的具体逻辑

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 优先从缓存中拿订阅的方法
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
		// 如果缓存中不存在,则通过下述的方式获取
        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;
        }
    }
通过反射方法获取订阅方法

​ 强制通过反射方法获取订阅方法

    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        // FindState可以理解为寻找订阅方法的状态容器.
        // 因为FindState内部存放了大量的数据,性能开销比较大,所以这里巧妙的使用了数据池优化
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        // 这里是通过`class`不为空来实现递归的解析类结构层次
        while (findState.clazz != null) {
            // 反射获取注解方法
            findUsingReflectionInSingleClass(findState);
            // 将解析动作转移到父类
            findState.moveToSuperclass();
        }
        // 回收数据到数据池
        return getMethodsAndRelease(findState);
    }

FindState可以理解为订阅信息的一种临时性容器,其内部存放了大量的零时性数据,其性能开销比较大.但出于业务需求,又需要经常使用这种容器,为了避免频繁的创建和销毁引起的性能浪费(内存抖动),这里使用了数据池模式优化.

    
	// 数据池中第一个非空数据,如果数据池中没有数据,则创建一个
	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();
    }

​ 在从数据池中取得数据后,为了防止脏数据,需要重新初始化

        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

​ 在完成数据的解析与查找后,都会调用getMethodsAndRelease方法

    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        // 临时性容器回收
        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;
    }

​ 在上述的方法中可以看到使用的FindState对象调用recycle方法释放内部数据,同时将数据放回数据池中,从而达到数据重用的效果.这是整个数据池模式过程.

​ 讲完数据池模式,再查看具体的订阅信息的采集.该部分的逻辑集中在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
            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);
            }
            // getDeclaredMethods跳过了父类的方法
            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) {
                        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)) {
                    // 订阅方法只能有一个订阅参数u
                    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");
            }
        }
    }

​ 通过反射的方式解析订阅信息算是比较简单,通过字节码文件Class对象,获取本类的定义的所有方法,再通过一连串的过滤条件,确认是符合条件的订阅方法后,将订阅信息汇总后加入FindState当中.具体的过滤条件有

  1. 订阅方法必须是public
  2. 订阅方法必须是非静态(static),非抽象(abstract),非合成,非桥接(后续两种类型都是编辑期间添加的)
  3. 订阅方法必须含有Subscribe的方法注解
  4. 订阅方法必须只含有一个参数

​ 需要需要注意的一个细节是,订阅方法的解析是有层级的,他总是先解析本类中的订阅方法,在上述的源码中,它是优先通过findState.clazz.getDeclaredMethods方法获取本类当中定义的方法,并没有获得从父类当中继承的方法,并且通过findState.skipSuperClasses = true记录了这种状态.在解析完本类中的方法后,他会继续通过moveToSuperclass方法以迭代的方式去解析上一级父类中的订阅方法

        void moveToSuperclass() {
            // 这里的参数是EventBuilder中设置的
            if (skipSuperClasses) {
                clazz = null;
            } else {
                // 获取父类
                clazz = clazz.getSuperclass();
                String clazzName = clazz.getName();
                // Skip system classes, this degrades performance.
                // Also we might avoid some ClassNotFoundException (see FAQ for background).
                if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") ||
                        clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) {
                    clazz = null;
                }
            }
        }

​ 如果用户设置了skipSuperClasses则不会继续去解析上级父类,否则会继续解析下去.在findUsingReflection方法中是通过一个while循环来判断findState.class == null来循环解析类结构层级的.

​ 至此,通过反射方式解析订阅方法流程到此结束.

通过注入的信息获取订阅方法

​ 除了通过反射的方式获取订阅方法,EventBus3.0还通过注解处理器实现编译期类型注入,从而极大的提高了一直被别人诟病的性能问题.这部分的代码从findUsingInfo开始

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        // 从数据池中获取状态容器
        FindState findState = prepareFindState();
        // 重新初始化
        findState.initForSubscriber(subscriberClass);
        // 通过判断findState.class是否为空,从而达到类多层级的解析,
        // 后续通过findState.moveToSuperclass方法,将解析动作向父类推进
        while (findState.clazz != 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();
        }
        // 将数据容器放回数据池中
        return getMethodsAndRelease(findState);
    }

​ 上述的逻辑基本跟通过反射方法差不多,相同部分都以注解方式标注.其中最大的不同点在于方法getSubscriberInfo.

    private SubscriberInfo getSubscriberInfo(FindState findState) {
        // 这里可以知道注解信息是存放在FindState.subscribeInfo字段中的.
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        // 这里subscriberInfoIndexes是用于存放所有注解解析的索引信息的.
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

​ 这里知道,编译时注解解析器解析注解生成的是SubscriberInfo,这是一个接口

public interface SubscriberInfo {
    // 注解所在的类
    Class<?> getSubscriberClass();
	// 注解的方法
    SubscriberMethod[] getSubscriberMethods();
	// 注解的父类的解析结果
    SubscriberInfo getSuperSubscriberInfo();
	// 是否解析了父类
    boolean shouldCheckSuperclass();
}

​ 解析器解析的所有结果会被最终放入到SubscriberMethodFinder类中的subscriberInfoIndexes容器中,追踪该数据的来源,它是通过构造方法注入的

    SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification,
                           boolean ignoreGeneratedIndex) {
        // 通过构造函数注入了
        this.subscriberInfoIndexes = subscriberInfoIndexes;
        this.strictMethodVerification = strictMethodVerification;
        this.ignoreGeneratedIndex = ignoreGeneratedIndex;
    }

​ 而SubsriberMethodFinder是在EventBus类中完成构建的

    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;
        // subsribeInfoIndex 来源于其builder中
        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;
    }

​ 而EventBus是使用构建者模式构建的,他实例化使用了EventBusBuilder类中的subscriberInfoIndexes,查看EventBusBuilder源码,发现最终通过如下的方法向其添加订阅信息索引的

    /** Adds an index generated by EventBus' annotation preprocessor. */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

​ 查看EventBusAnnotationProcessor源码,其中确实有通过该方法注入订阅信息

    private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException {
        for (TypeElement subscriberTypeElement : methodsByClass.keySet()) {
            if (classesToSkip.contains(subscriberTypeElement)) {
                continue;
            }

            String subscriberClass = getClassString(subscriberTypeElement, myPackage);
            if (isVisible(myPackage, subscriberTypeElement)) {
                writeLine(writer, 2,
                        "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,",
                        "true,", "new SubscriberMethodInfo[] {");
                List<ExecutableElement> methods = methodsByClass.get(subscriberTypeElement);
                writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage);
                writer.write("        }));\n\n");
            } else {
                writer.write("        // Subscriber not visible to index: " + subscriberClass + "\n");
            }
        }
    }

​ 至于如何通过注解处理器解析注解,在此不做过多深究.

订阅

​ 在获取到订阅方法后,就要实行真正的订阅动作了

 // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        // 订阅的事件类型
        Class<?> eventType = subscriberMethod.eventType;
        // 将订阅的事件类型与订阅者组成Subscription实例
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        // subscriptionsByEventType会记录没一个事件的所有订阅信息
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            // 一个订阅着不能重复订阅相同的消息类型
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
		// 这里将订阅信息通过priority的优先级插入到数组中,按照优先级高的排序
        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;
            }
        }
		// 这里记录没一个suscriber的类型
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, 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);
            }
        }
    }

​ 在订阅过程中,解析的订阅方法与订阅者一起组成了Subscription对象.这个类的实例对象是EventBus各种操作的基本单位,如订阅,解除订阅,发送信息等.随后,新注册的订阅者会被依据不同的订阅消息类型放在同一个容器内,并且在该容器内以优先级参数priority.同时记录订阅者的类型.在完成这些动作后,EventBus需要确定订阅者订阅的消息类型是否是粘性消息,如果是,则需要将最新存储的粘性消息发送给订阅者.

    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中会将事件发送订阅者执行订阅方法,如果没猜错的话就是将解析的订阅方法继续通过反射invoke.但是订阅方法是可以定义线程模式的.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 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);
        }
    }

​ 这里可以看到,根据不同的线程模型,执行不同的策略.

POSTING

​ 这应该是最简单的线程模型了.在哪里发布信息,就在哪里执行订阅方法,查看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);
        }
    }
MAIN

​ 这种线程模型应该要求执行环境在UI线程

                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }

​ 如果当前线程是在UI线程中,直接调用订阅方法,否则通过mainThreadPoster处理.mainThreadPoster是一个Poster.这是一个接口

interface Poster {

    /**
     * Enqueue an event to be posted for a particular subscription.
     *
     * @param subscription Subscription which will receive the event.
     * @param event        Event that will be posted to subscribers.
     */
    void enqueue(Subscription subscription, Object event);
}

​ 它主要为要发布的事件实现排列等待的功能.

​ 在EventBus中,它的实例化代码如下

        mainThreadSupport = builder.getMainThreadSupport();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;

​ 它是由MainThreadSupport实例创建的.

public interface MainThreadSupport {

    boolean isMainThread();

    Poster createPoster(EventBus eventBus);

    // 静态内部实现类
    class AndroidHandlerMainThreadSupport implements MainThreadSupport {

        private final Looper looper;

        // 在其构造函数中需要传如一个Looper实例
        public AndroidHandlerMainThreadSupport(Looper looper) {
            this.looper = looper;
        }

        @Override
        public boolean isMainThread() {
            return looper == Looper.myLooper();
        }

        @Override
        public Poster createPoster(EventBus eventBus) {
            // 这里知道他返回的是HandlerPost对象
            return new HandlerPoster(eventBus, looper, 10);
        }
    }
}

​ 在EventBus的构建者类中,部分的源码如下

    // 这里获取MainThreadSupport
	MainThreadSupport getMainThreadSupport() {
        if (mainThreadSupport != null) {
            return mainThreadSupport;
        } else if (AndroidLogger.isAndroidLogAvailable()) {
            Object looperOrNull = getAndroidMainLooperOrNull();
            return looperOrNull == null ? null :
                    new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
        } else {
            return null;
        }
    }
	
    static Object getAndroidMainLooperOrNull() {
        try {
            return Looper.getMainLooper();
        } catch (RuntimeException e) {
            // Not really a functional Android (e.g. "Stub!" maven dependencies)
            return null;
        }
    }

​ 一眼就可以看出切换UI线程的方式是通过Handler.通过Looper.getMainLooper方法获取主线程的Looper,创建HandlerPoster对象.

/*
*  1. 这里PendingPostQueue充当的是`MessageQueue`的角色,两者的功能非常相近
* 
*/
public class HandlerPoster extends Handler implements Poster {
	// 自定义的消息队列 MessageQueue
    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;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        // 这里应该也用了数据池优化
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        // 入队是同步的动作
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                // 每一次的入队都通过sendMessage唤醒消息的执行
                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;
        }
    }
}

HandlerPoster继承Handler.这里需要注意的一些细节是在HandlerPoster内部,自己实现了一个PendingPostQueue.它为什么要这样做?其实,道理很简单.第一,它实现的Poster接口要求它必须实现给消息排序的功能(注册方法有可能存在耗时业务),第二,则是原生的MassageQueue装载的对象是Message,而Message对象已经无法装载数据了.所以,此时只能自己去实现,但是,但是,其内部的功能与原来与原生MessageQueue是一样的.所以,此部分的代码与Handler机制部分源码的功能非常接近.

BACKGROUND

​ 这种线程模型应该要求执行环境在后台线程.

​ 直接查看其Poster

final class BackgroundPoster implements Runnable, Poster {
	// 他的顺序也是通过`PendingPostQueue`来实现的
    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }
	
    // 如对
    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                // 这里使用了EventBus线程池
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

​ 这里没有使用Handler技术.BackgroundPoster本身是一个Runnable,在其run方法中不断去轮循队列中的Subscription,只要存在未执行的的Subscription就会去执行.它的执行环境是EventBus线程池中的线程.需要注意的时,它的执行步骤都是同步的,所以,意味着,定义的订阅函数最好不要有太多耗时的业务,避免事件的发送延迟.

ASYNC

​ 这种线程模型应该要求执行环境在后台线程,并且是异步的.

class AsyncPoster implements Runnable, Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    AsyncPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        eventBus.getExecutorService().execute(this);
    }

    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

}

​ 这里的代码跟BACKGROUND中唯一的不同就是没有加入同步的操作,这意味着,下个消息的执行不依赖上个消息的执行状态,只要有消息,并且线程池中有空闲的线程,订阅方法就会被调用.在这种情况下,订阅方法是可以执行耗时的动作的.

发送消息

​ 最后看看如何发送消息

    public void post(Object event) {
        // EventBus会为每个发送事件的线程保存一个线程变量
        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;
            }
        }
    }

​ 这里会为调用post方法线程创建一个线程间变量,改变量用于保存发送数据.ThreadLocaleHanlder机制中也出现过.在确定该线程队列中存在未post的消息,则会通过postSingleEvent方法逐个发送.后续的代码比较简单,不再继续分析

​ 至此,EventBus的大体流程分析完毕.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值