阅读 876

Android-开源框架分析-【EventBus】

前言

在项目中遇到了有关EventBus数据方面的问题,于是就参考源码梳理一下整个数据流程,最后整理输出。

简介

EventBus是一个基于观察者模式的发布/订阅事件总线,解决了以往广播在组件间通信的不安全、耗时问题,替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息。

EventBus

优缺点

优点->简化组件之间的通信,实现解耦使业务简洁,高效,可以自己设置事件处理的线程以及优先级。
缺点->需要维护很多事件类。

使用

1. 定义事件:

    public static class MessageEvent { /* Additional fields if needed */ }
复制代码

2. 准备订阅者: 申明并注解你的订阅方法, 指定线程模式(可选)

@Subscribe(threadMode = ThreadMode.MAIN)  
public void onMessageEvent(MessageEvent event) {/* Do something */};
复制代码

在使用的类中,注册和解注册订阅者,如Activity/fragment中:

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

@Override
public void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}
复制代码

3. 发送事件:

EventBus.getDefault().post(new MessageEvent());
复制代码

内部实现

1.EventBus.getDefault().register(this);

注册给定的订阅用户以接收事件。订阅者对接收事件不再感兴趣后,必须调用{@link #unregister(Object)}。

 public void register(Object subscriber) {
      //通过反射获取订阅者Class对象
      Class<?> subscriberClass = subscriber.getClass();
      //1.5
      List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
      synchronized (this) {
          //遍历订阅
          for (SubscriberMethod subscriberMethod : subscriberMethods) {
              //2
              subscribe(subscriber, subscriberMethod);
          }
      }
 }
复制代码

通过Class对象获取它的订阅事件的集合

  • 1.SubscriberMethodFinder#List findSubscriberMethods(Class<?> subscriberClass)
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
        //这个Map key为注册事件的类(比如某个Activity),value为承载着事件类(MessageEvent)和处理事件的方法(onMessageEvent(MessageEvent event))
      //先从此处查找 不为空返回 为空 就添加到map中
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            //1.1 获取所有订阅者的方法列表
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        //不为空 就添加到map中
        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;
        }
    }


1.1 SubscriberMethodFinder#List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass)

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //从FIND_STATE_POOL (private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];  POOL_SIZE->4)
        //中获取FindState对象
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
          //第一次为null
            if (findState.subscriberInfo != null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                //通过反射获取订阅者类中的所有方法
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        //从findState中获取订阅者所有方法的集合
        return getMethodsAndRelease(findState);
    }
复制代码
  • 2.EventBus#subscribe(Object subscriber, SubscriberMethod subscriberMethod)
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //获取事件类型的Class对象
        Class<?> eventType = subscriberMethod.eventType;
        //将信息封装到对象中
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //根据事件类型查找对应的CopyOnWriteArrayList
        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);
            }
        }
        
        //根据优先级将新构建的subscription(subscriber, subscriberMethod)添加到CopyOnWriteArrayList中
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
        //如果是sticky事件 调用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);
            }
        }
    }
复制代码

注册部分主要通过通过订阅者的Class对象获取其中的订阅方法,将方法和订阅者绑定,之后又处理了粘性事件。

2. EventBus.getDefault().post(new MessageEvent());

    public void post(Object event) {
        //currentPostingThreadState(是ThreadLocal)获取PostingThreadState 
        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()) {
                    //3
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

    final static class PostingThreadState {
       final List<Object> eventQueue = new ArrayList<>(); // 线程的事件队列
        boolean isPosting; //是否正在发送
        boolean isMainThread; //是否在主线程中发送
        Subscription subscription; //关于事件的封装
        Object event; //事件对象
        boolean canceled; //是否被取消发送
    }
复制代码
  • 3.EventBus#postSingleEvent(Object event, PostingThreadState postingState)
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            //查找所有Class对象,包括超类和接口
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                //调用postSingleEventForEventType方法发送事件
                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));
            }
        }
    }

    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) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    //发送事件
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }
  
    //粘性事件会直接调用这个
    //根据注解上的线程模式在不用的线程调用
    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING://直接反射调用方法 不切换线程
                invokeSubscriber(subscription, event);
                break;
            case MAIN://在主线程直接反射调用 
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {        //否则加入到列队中到主线程调用
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED://与MAIN类似
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    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方法主要将事件加入集合并且集合还有数据就一直发送,然后获取所有订阅该事件类的订阅者,判断他们需要运行的线程来决定在哪个线程运行。

3.EventBus.getDefault().postSticky(new MessageEvent());

    //加入到粘性事件列表中供之后判断
    public void postSticky(Object event) {
        synchronized (stickyEvents) {
            stickyEvents.put(event.getClass(), event);
        }
        //发送事件
        post(event);
    }
复制代码

将数据加入到粘性事件列表在registe方法中判断是否post事件

4.EventBus.getDefault().unregister(this);

    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());
        }
    }
复制代码

总结

到这里EventBus源码流程就结束了,它的源码相较于其他来说还是比较简单的,如果文中有不足之处望指出。

文章分类
Android
文章标签