Android EventBus 3.1.1最新源码分析

EventBus 3.1.1源码分析

      • 前言
      • EventBus构造方法
      • 订阅者注册
        • 查找订阅者方法
        • 注册过程
      • 发送事件
      • 订阅者取消注册

前言

EventBus 是一款在 Android 开发中经常使用的发布/订阅事件总线框架,将事件的接收者和发送者分开;简化了组件之间的通信,使用简单、效率高、体积小!由于经常使用到,所以我们深入理解该框架的原理就很有必要了,下面我们就来分析一下EventBus原理。

EventBus构造方法

大家都知道当我们在使用EventBus时,首先会调用EventBus.getDefault()方法来获取EventBus的实例。那我们来看一下getDefault()方法,代码如下:

	/** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

这是一个双重检查模式单例模式。
接下来是EventBus构造方法,代码如下:

	/**
     * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
     * central bus, consider {@link #getDefault()}.
     */
    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;
    }

这里DEFAULT_BUILDER是默认的EventBusBuilder:

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

这里调用了EventBus的另外一个构造方法,采用了建造者模式,通过构造EventBusBuilder来配置EventBus。

订阅者注册

获取到EventBus的实例以后就调用register(this)方法将订阅者注册到EventBus中,register()方法代码如下:

	public void register(Object subscriber) {
        Class subscriberClass = subscriber.getClass();
        List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//得到一个SubscriberMethod的集合,就是传进来的订阅者的所有订阅方法
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {//遍历订阅者的订阅方法来完成订阅者的注册操作
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

register方法做了两件事:一件事是查找订阅者的订阅方法,另一件事是订阅者的注册。
SubscriberMethod类主要用来保存订阅方法的Method对象、线程模式、事件类型、优先级、是否是黏性事件等属性。

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;

    public SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }
	....
	....
	其他方法
	....
	....
}

查找订阅者方法

接下来看看findSubscriberMethods(subscriberClass)方法代码:

	List findSubscriberMethods(Class subscriberClass) {
        List subscriberMethods = METHOD_CACHE.get(subscriberClass);//从缓存中查找是否有订阅方法的集合
        if (subscriberMethods != null) {//如果找到就return 
            return subscriberMethods;
        }
		//如果缓存中没有,则根据 ignoreGeneratedIndex属性的值来选择采用何种方法来查找订阅方法的集合
		//ignoreGeneratedIndex 的默认值是 false,可以通过EventBusBuilder来设置它的值
        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;
        }
    }

ignoreGeneratedIndex 属性表示是否忽略注解器生成的 MyEventBusIndex,具体可以看官网:http://greenrobot.org/eventbus/documentation/subscriber-index/

项目中经常通过EventBus单例模式来获取默认的EventBus对象,也就是ignoreGeneratedIndex为false的情况,这种情况调用了findUsingInfo(subscriberClass)方法,代码如下:

	private List findUsingInfo(Class subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);//获取订阅者信息
            if (findState.subscriberInfo != null) {
            	//如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取到subscriberInfo
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();//得到订阅方法相关的信息
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {//没有配置MyEventBusIndex
                findUsingReflectionInSingleClass(findState);//将订阅方法保存到findState中
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);//对findState做回收处理并返回订阅方法的List集合
    }

在开始查找订阅方法的时候并没有忽略注解器为我们生成的索引 MyEventBusIndex。

如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取subscriberInfo(这个参考上面ignoreGeneratedIndex为true的情况所调用的方法findUsingReflection(subscriberClass));
没有配置MyEventBusIndex便会执行findUsingReflectionInSingleClass(findState)方法;

最后再通过getMethodsAndRelease(findState)方法对findState做回收处理并返回订阅方法的List集合,这里贴一下getMethodsAndRelease(findState)方法代码:

	private List getMethodsAndRelease(FindState findState) {
        List 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;
    }

默认情况下是没有配置MyEventBusIndex的,所以就会调用findUsingReflectionInSingleClass(findState)方法,代码如下:

	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();
            //根据方法的类型、参数和注解来找到订阅方法。找到订阅方法后将订阅方法的相关信息保存到findState中。
            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方法里面遍历SubscriberMethod对所有的订阅方法进行注册,调用了subscribe(subscriber, subscriberMethod)方法,代码如下:

	// Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class eventType = subscriberMethod.eventType;
        //根据subscriber(订阅者)和subscriberMethod(订阅方法)创建一个Subscription(订阅对象)
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //根据eventType(事件类型)获取Subscriptions(订阅对象集合)
        CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
        	//如果Subscriptions为null则重新创建,并将Subscriptions根据eventType保存在subscriptionsByEventType中
            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;
            }
        }

        List> subscribedEvents = typesBySubscriber.get(subscriber);//通过subscriber获取subscribedEvents事件类型集合
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();//为空重新创建对象
            typesBySubscriber.put(subscriber, subscribedEvents);//根据subscriber将subscribedEvents存储在typesBySubscriber集合中
        }
        subscribedEvents.add(eventType);//将eventType添加到subscribedEvents中

        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).
                //从stickyEvents事件保存队列中取出该事件类型的事件发送给当前订阅者
                Set, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry, 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);
            }
        }
    }

subscribe()方法主要就是做了两件事:
1、将Subscriptions根据eventType封装到subscriptionsByEventType中,将subscribedEvents根据subscriber封装到typesBySubscriber中;
2、对黏性事件的处理。

发送事件

我们通过post方法来对事件进行发送,所以我们看一下post()方法源码:

	/** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List 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;
            }
        }
    }
 
  

PostingThreadState 保存事件队列和线程状态信息,currentPostingThreadState.get()方法获取到PostingThreadState 对象,currentPostingThreadState代码如下:

private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

上面从PostingThreadState对象中取出事件队列,然后再将当前的事件插入事件队列;通过postSingleEvent(eventQueue.remove(0), postingState)方法处理和移除该事件,代码如下:

	private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class eventClass = event.getClass();
        boolean subscriptionFound = false;
        //eventInheritance 表示是否向上查找事件的父类,它的默认值为 true,可以通过在EventBusBuilder中进行配置
        if (eventInheritance) {
            List> eventTypes = lookupAllEventTypes(eventClass);//找到所有的父类事件并存在List中
            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 subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);//同步取出该事件对应的Subscriptions订阅对象集合
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
        	//遍历Subscriptions,将事件 event 和对应的 Subscription(订阅对象)传递给postingState
            for (Subscription subscription : subscriptions) 
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);//调用postToSubscription方法对事件进行处理。
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

接下来看postToSubscription(subscription, event, postingState.isMainThread)方法代码:

	private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
		//取出订阅方法的threadMode,根据threadMode来分别处理
        switch (subscription.subscriberMethod.threadMode) {
        	// 默认的线程模式,在那个线程发送事件就在那个线程处理事件
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            // 在主线程处理事件
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);// 如果在主线程发送事件,则直接在主线程通过反射处理事件
                } else {
                	// 如果是在子线程发送事件,则将事件入队列,通过Handler切换到主线程执行处理事件
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            // 无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
            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);
        }
    }

根据threadMode来分别处理。如果threadMode是MAIN,提交事件的线程是主线程,则通过反射直接运行订阅的方法;若其不是主线程,则需要mainThreadPoster 将我们的订阅事件添加到主线程队列中。mainThreadPoster是HandlerPoster类的一个实例,继承自Handler,通过Handler将订阅方法切换到主线程执行,看下该类的主要实现,代码如下:

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;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
    	// 用subscription和event封装一个PendingPost对象
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);// 加入队列
            if (!handlerActive) {
                handlerActive = true;
                 // 发送开始处理事件的消息,handleMessage()方法将被执行,完成从子线程到主线程的切换
                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);// 进一步处理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;
        }
    }
}

订阅者取消注册

取消注册就调用unregister()方法,代码如下所示:

	/** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        List> subscribedTypes = typesBySubscriber.get(subscriber);//通过subscriber找到subscribedTypes事件类型集合
        if (subscribedTypes != null) {
            for (Class eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);//遍历 subscribedTypes
            }
            typesBySubscriber.remove(subscriber);//将subscriber对应的eventType从 typesBySubscriber中移除
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

接下来看unsubscribeByEventType(subscriber, eventType)方法,代码如下:

	/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class eventType) {
    	//通过eventType来得到对应的Subscriptions订阅对象集合
        List subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                //如果Subscription(订阅对象)的subscriber(订阅者)属性等于传进来的subscriber,则从Subscriptions中移除该Subscription
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);//移除该Subscription
                    i--;
                    size--;
                }
            }
        }
    }

以上就是EventBus的源码分析。

你可能感兴趣的:(Android开发,Android开源框架源码解析)