美文网首页
Android EventBus源码解析(下)

Android EventBus源码解析(下)

作者: Android程序员老鸦 | 来源:发表于2021-05-27 17:54 被阅读0次

上篇分析了EventBus查找所有的订阅集合List<SubscriberMethod>的过程,这篇继续往下走,分析一下订阅的流程:

 public void register(Object subscriber) {

        Class<?> subscriberClass = subscriber.getClass();
        //通过类名也就是activity的类查找List<SubscriberMethod>集合
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        //开始循环订阅每个方法
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //获取订阅方法的入参类型,也即是事件类名
        Class<?> eventType = subscriberMethod.eventType;
        //又搞了个封装类Subscription,封装了事件订阅所在的类名和订阅的方法信息
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //subscriptionsByEventType的格式是Map<Class<?>, CopyOnWriteArrayList<Subscription>>
        //缓存用的map,存放的是事件类型和Subscription集合的键值对
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            //为空则新建了一个空的subscriptions,并把当前的事件类型和这个subscriptions存起来
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            //同一个方法订阅了两次,报错
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
        //根据优先级排序装入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;
            }
        }
        //又是个缓存map,typesBySubscriber的格式是Map<Object, List<Class<?>>>,存放的是订阅所在类名
        //和订阅事件类型集合的键值对,简单来说就是通过这个map可以方便拿到该类下所有的订阅事件类型
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
            //放入缓存
        subscribedEvents.add(eventType);
        //省略干扰代码。。。
    }

看下来似乎就是把找到的订阅事件信息整理放在了两个map上:

//存放的是事件类型和Subscription集合的键值对
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//存放的是订阅所在类名和订阅事件类型集合的键值对
private final Map<Object, List<Class<?>>> typesBySubscriber;

猜测一波,后续post发送事件后肯定就是对这两个map进行操作了
接下来看看post(event)方法:

   //推送流程1
    public void post(Object event) {
        //currentPostingThreadState是一个ThreadLocal类型,这是java提供的一个线程内部的存储类,
        // 可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据,这里不详细分析
        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;
            }
        }
    }
    //推送流程2
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        //eventInheritance是初始化eventBus的一个值,大意是是否一并通知该订阅事件的父类或实现的接口类的订阅事件,默认是true
        //比如 A extends B implements C  发布者post(A),那么找订阅者的时候不仅要找订阅了事件A的订阅者
        // 还要找订阅了B和C的订阅者
        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 {
            //简单点理解可以看这里,上面的分支也最终走到了postSingleEventForEventType()方法
            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));
            }
        }
    }
    //推送流程3
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            //开始用到subscriptionsByEventType这个map了,通过事件类型取出所有订阅了该事件的方法信息集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        //简单判空处理
        if (subscriptions != null && !subscriptions.isEmpty()) {
            //循环遍历这个list
            for (Subscription subscription : subscriptions) {
                //在线程存储对象里记录下发送的事件对象和订阅了该事件的信息
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted;
                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;
    }
//推送流程4 按照订阅时设置的调用线程分别处理
 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);
        }
    }

最后post事件后会到invokeSubScriber()方法,enqueue()方法只是做个异步调用最后还是会走到invokeSubScriber(),看方法名就知道是用到了反射去执行订阅方法:

 void invokeSubscriber(Subscription subscription, Object event) {
        try {
         //用subscription保存到的方法实例invoke()一下,最终完成了用事件推送来达到订阅方相应的目的
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

至此,从订阅到post事件的流程讲完了,主要核心是缓存的设计,APT和反射的运用。最后,还有一个map在post过程中好像没被用到就是:

//存放的是订阅所在类名和订阅事件类型集合的键值对
private final Map<Object, List<Class<?>>> typesBySubscriber

看他的键值对设计想必应该是用在判断/解除注册里可以方便的查找,看了看源码发现果然是:

//用来判断该类是否注册过
 public synchronized boolean isRegistered(Object subscriber) {
        return typesBySubscriber.containsKey(subscriber);
    }
 //解除注册
    public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                //相应的在subscriptionsByEventType这个map里也会移除调订阅信息
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

OK,分析完成!看完源码后只是把主干流程梳理了一下,EventBus作为优秀的开源项目,其设计思想还是很值得反复研究的,多看看这种成熟优秀的项目对于自己的代码能力也是有很大的提升!

相关文章

网友评论

      本文标题:Android EventBus源码解析(下)

      本文链接:https://www.haomeiwen.com/subject/xchdsltx.html