EventBus相关

看文章前提一句,重点看代码里面注释

一.EventBus是什么?

EventBus是一款针对Android优化的发布/订阅事件总线

二.How to Use?

    //就这几个方法,不再赘述,默认你用过
    fun onCreate() {
        EventBus.getDefault().register(this)
    }

    fun onDestory() {
        EventBus.getDefault().unregister(this)
    }

    fun send() {
        EventBus.getDefault().post(DemoEvent())
    }

    @Subscribe
    public fun onReceiveDemoEvent(event: DemoEvent) {
        //balabala 
    }

三.源码解析(针对3.1.1版本)

1.EventBus.getDefault().register(Object) 注册EventBus

public void register(Object subscriber) {
        //注册对象获取class
        Class<?> subscriberClass = subscriber.getClass();
        //从订阅查找器里查找方法
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            //遍历把方法订阅方法
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

subscriberMethodFinder 对象从哪里来?

先从构建说起,反手就是一个建造者模式
public class EventBusBuilder {
    //EventBus的线程池,无限大,可复用
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    //布尔值全部为标志位,跟你平时加flag执行不同逻辑一样,不需要特地理解,看具体用法
    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;
    //通过APT注解,在编译时就生成对应解析注解为优化方式,这个默认为空,即你找不到
    List<SubscriberInfoIndex> subscriberInfoIndexes;
    //写日志的玩意儿
    Logger logger
    //内部就2个方法,判断是否为主线程,创建handler(作者给这些handler起名叫poster发射器)
    MainThreadSupport mainThreadSupport;
    ......
}
    //获取单例
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }
    //虽然 public ,别调用,没啥用
     public EventBus() {
        this(DEFAULT_BUILDER);
    }
      //就是各种赋值,赋值,
     EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        //一些事件集合哈,发送的事件就是往这里的,说到底还是往map里面存
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        //3种发射器,区别后面讲
        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);
        //后面这些就不讲了,就是各种flag的赋值,然后把线程池给单例
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }
    

SubscriberMethodFinder 字面意思,订阅方法的查找器
SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification,boolean ignoreGeneratedIndex)

参数作用
1.subscriberInfoIndexes 这个呢其实就是apt的插件生成的一些EventBusIndex,注入进去
2.strictMethodVerification 默认值false,如果为true,会抛异常哈。具体点到这个类看看就可以
3.ignoreGeneratedIndex 忽略注解,仅通过反射方式拿取,默认false哈,就是会去找index那种

下面看看这个类里面的方法,回到主题

一开始讲的这个EventBus.getDefault().register(XXX)方法里面

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

也就是这个方法 findSubscriberMethods

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //有缓存直接取了哈。METHOD_CACHE又是一个hashMap
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            //刚才说过的,开了ignoreGeneratedIndex就直接用反射了
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            //findUsingInfo 这个方法是真正根据要订阅的类查找订阅方法了
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        if (subscriberMethods.isEmpty()) {
          //这里提一嘴,平时你们写了register但是类里又没有Subscribe注解,你App就炸了,这里报的
            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;
        }
    }

找到findUsingInfo这个方法

  private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();//准备一个查找的state
        findState.initForSubscriber(subscriberClass);//根据当前类初始化 链接1
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);//从subscriberInfoIndexes里面找方法,链接2
            if (findState.subscriberInfo != null) {
                //subscriberInfo 这个里面有方法名什么的,就是提前已经根据注解解析完了
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    //检查添加方法,这里面会抛出异常,总之不要有同名方法。没问题就是add
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                //没找到只好用反射的方式了。。链接3
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        //最后把订阅好的方法,返回去。然后回收findState。就是考虑复用。。
        return getMethodsAndRelease(findState);
    }

    //相关方法哈.看title找下把
    //链接1
    void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }
    
    //链接2
    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;
            }
        }
        if (subscriberInfoIndexes != null) {
            //这里看到了么。。眼熟的subscriberInfoIndexes ,就是apt注解提前生成的类里,遍历去找
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

//链接3 这就是个反射。先根据类,获取注解,然后解析。后面一样的。。也是查找下是不是有,然后添加添加。
//2.X版本方式。。以前人们不是天天说,反射,影响效率么,所以现在用原则上用上面那个效率高。
 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 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)) {
                    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");
            }
        }
    }

拿到订阅的方法之后,要跟对象绑定起来,在register的方法的遍历里
subscribe(subscriber, subscriberMethod);
参数1就是你register的传进来的对象,参数2是这个对象类里面找到的方法

    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

        //这里开始,是先去把方法放到subscriptionsByEventType 这个事件类型的缓存
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        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);
            }
        }

        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这个就是isRegister,unRegister使用的哈。
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
        
        //以下就是stikyEvent相关,checkPostStickyEventToSubscription,如果本地有粘性事件
        //注册粘性事件的时候一并取了
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                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);
            }
        }
    }

断点看实际效果,可以看到通过subscriberMethodFinder 找到的SubscriberMethod有参数名,对应方法,线程模式等等


SubscriberMethod.png

再看 subscriptionsByEventType 缓存的对象,就是把事件类型作为key,前面所拿到的Subscription作为value,进行缓存


subscriptionsByEventType.png

最后看typesBySubscriber缓存的对象,就是把object作为key,该object订阅对应的事件类型作为value
typesBySubscriber.png

2.EventBus.getDefault().unregister(Object) 解注册EventBus

public synchronized void unregister(Object subscriber) {
        //subscribedTypes register的时候往这个里面放过,解注册的时候移除
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                //这个遍历的for循环里面,把对应的事件全部移除了噢
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber ...: " + subscriber.getClass());
        }
    }
 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--;
                }
            }
        }
    }

3.EventBus.getDefault().post(EventObject())发送事件

最后一步了,发送事件

    public void post(Object event) {
        //currentPostingThreadState  这个是ThreadLocal,可以看作数据结构map,key为线程,value为你设定的对象,每个线程不同。
        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;
            }
        }
    }
 private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        .........
            //回调这个方法
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        ........
}

 private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
             //从订阅的方法里,取出这个方法
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                //取出对应的事件跟subscription
                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;
    }

POSTING,MAIN,MAIN_ORDERED,这些就是订阅事件的线程模式

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

关于poster,其实就是一开始创建的线程池中取出线程来运行,其中比较特殊的是mainThreadPoster,这个其实是handler,把mainLooper取出来给他,创建出来的

    Object getAndroidMainLooperOrNull() {
        try {
            return Looper.getMainLooper();
        } catch (RuntimeException e) {
            // Not really a functional Android (e.g. "Stub!" maven dependencies)
            return null;
        }
    }

    class AndroidHandlerMainThreadSupport implements MainThreadSupport {

        private final Looper looper;

        ...

        @Override
        public Poster createPoster(EventBus eventBus) {
            return new HandlerPoster(eventBus, looper, 10);//这里
        }
    }
    //最初的构造者模式中,对应的地方。
    EventBus(EventBusBuilder builder) {
        ......
        mainThreadSupport = builder.getMainThreadSupport();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
      .....  
    }

最后来看看invokeSubscriber(Subscription subscription, Object event)

void invokeSubscriber(Subscription subscription, Object event) {
        try {
            //其实就是调用method的invoke方法,其中subscription.subscriber是订阅对象,event是对应发送的事件
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }
至此EventBus整体流程完毕,建议结合源码断点,自己理解下。早在几年前,就说EventBus需要被淘汰,实际上现在还有很多公司在用。看看源码不吃亏,理解下设计理念就好。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。