Andorid 核心源码(一、深入理解 EventBus 源码)

627 阅读15分钟

前言: 迷茫,本就是青春该有的样子,但不要让未来的你,讨厌现在的自己。

一、概述

  前面的文章提到了EventBus是发布/订阅者模式,适用于Android和Java的发布/订阅事件总线。主要功能是替代Intent、Handler、BroadCast在Activity、Fragment、Service线程之间传递消息。它能够简化应用组件间的通信,解耦(有效分离)事件的发送者和接收者,避免复杂和容易出错的依赖和生命周期问题,开销小,代码更优雅。

在这里插入图片描述

EventBus的官网原理图,发布者通过EventBus发布事件,订阅者通过EventBus订阅事件,当发布者发送事件时,订阅该事件的订阅者的事件处理方法将被调用。从图中看出,发布者发送一个事件时,则该事件将会同时传递给一个或多个该事件的订阅者。

二、源码解析EventBus

2.1 注册事件

我们主要讲解一下EventBus的源码的实现。注册事件的方式如下:

EventBus.getDefault().register(this);

通过EventBus.getDefault()获取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;
    }

下面看看EventBus的构造方法里面做了什么事情:

   public EventBus() {
        this(DEFAULT_BUILDER);
    }

this()表示EventBus的一个构造方法,DEFAULT_BUILDER表示默认构建的EventBusBuilder,用于构造EventBus

 	private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

EventBus的构造方法中,通过EventBusBuilder来进行配置:

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

通过建造者模式EventBusBuilder对EventBus的相关信息配置,当然我们也可以通过EventBusBuilder更改EventBus的配置:

    EventBus.builder()
            .sendSubscriberExceptionEvent(false)
            .sendNoSubscriberEvent(false)
            .build()
            .register(this);

通过build()构建一个当前配置的EventBus实例,register(this)也可以注册事件

   public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        //1.找出当前订阅者的所有订阅方法
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {//同步
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);//2.对订阅者方法注册
            }
        }
    }

注册事件里面只做了两件事:

  • 找出当前订阅者的所有订阅方法;
  • 对订阅者方法进行注册。

查找订阅者方法返回一个SubscriberMethod对象的集合,SubscriberMethod是方法的相关属性对象

public class SubscriberMethod {
    final Method method;//方法对象
    final ThreadMode threadMode;//执行线程
    final Class<?> eventType;//接收事件的类型
    final int priority;//事件优先级
    final boolean sticky;//是否为粘性事件
    /** Used for efficient comparison */
    String methodString;
    }

findSubscriberMethods()开始查找方法:

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    	//METHOD_CACHE是一个ConcurrentHashMap,根据subscriberClass保存了SubscriberMethod,提高保存效率,防止重复查找
    	//从缓存中查找是否有订阅的方法集合,如果有则直接返回
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
		//ignoreGeneratedIndex默认为false,如果使用默认的EventBusBuilder,则忽略注解生成器
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }     
        METHOD_CACHE.put(subscriberClass, subscriberMethods);//缓存查找到的订阅事件方法
        return subscriberMethods; 
    }

findSubscriberMethods()首先去缓存中查找,如果找到则直接返回;如果找不到则去下一级查找,找到后缓存起来,如果我们使用默认方式获取EventBus对象,即ignoreGeneratedIndex = false,那么来到findUsingInfo()

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    	//FindState是包含订阅者方法和订阅者信息的对象,包含了所有订阅者的方法、事件类型、保存方法的key等信息
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        //循环判断
        while (findState.clazz != null) {//初始状态下的findState.clazz就是subscriberClass
            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();//修改findState.clazz为subscriberClass的父类class
        }
        //将findState中的SubscriberMethod集合放到一个新的List中并且返回,释放掉findState
        return getMethodsAndRelease(findState);
    }

findUsingInfo()会在当前要注册的类以及父类中查找订阅者方法,FindState类用来辅助查找订阅事件方法,具体过程在findUsingReflectionInSingleClass()方法中,它通过反射查找订阅事件方法

   private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
    	······
        //遍历当前类方法,查找到符合条件的
        for (Method method : methods) {
            int modifiers = method.getModifiers();//获得方法修饰符
            //如果是public,但非abstract、static等
            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];
                        //判断findState的anyMethodByEventType是否添加过eventType的方法,没有则返回true
                        if (findState.checkAdd(method, eventType)) {
                        	//获取线程模式
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //通过实践类型、线程模式、优先级、是否为粘性事件创建一个SubscriberMethod,添加到subscriberMethods方法集合中
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                }
            } 
        }
    }

到这里register()findSubscriberMethods()查找订阅者事件方法分析完了,就是找到当前注册类以及父类中订阅事件的方法的集合,接着来看看register()subscribe()方法:

  private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
  		//获取当前事件方法的事件类型
        Class<?> eventType = subscriberMethod.eventType;
        //Subscription中保存了要注册的类对象以及当前的subscriberMethod方法体
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //subscriptionsByEventType是一个以eventType为key,Subscription为value的键值对HasMap
        //subscriptionsByEventType是否存在该事件类型的值
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        //如果不存在subscriptions则创建一个subscriptions,并保存到subscriptionsByEventType中
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } 

        int size = subscriptions.size();
        //将上面的newSubscription添加到subscriptions中保存
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
		//typesBySubscriber是一个注册类对象为key,该注册类的事件类型集合为value的HasMap
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        //如果不存在subscribedEvents则创建一个,并保存到typesBySubscriber中
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        //保存当前订阅事件的事件类型
        subscribedEvents.add(eventType);
		//粘性事件--后面另外分析
        if (subscriberMethod.sticky) {
        ······
        }
    }

这就是注册的核心流程,所以subscribe()主要是获得以事件类型为key,Subscription为value的subscriptionsByEventType,获得以注册类对象为key,该注册类的事件类型集合为value的typesBySubscriber,在发送事件的时候使用subscriptionsByEventType完成事件的处理,在注销EventBus的时候对subscriptionsByEventTypetypesBySubscriber相关资源释放

注册订阅者流程:

  • 1.通过registere()注册一个订阅者;
  • 2.获取当前订阅者所有订阅方法(方法缓存METHOD_CACHE如果有则直接返回,没有则通过反射和注解@Subscribe注解找到方法名集合并保存到METHOD_CACHE中)
  • 3.根据订阅者的订阅事件类型,将订阅者存储到以订阅者事件类型为key,所有订阅者信息为value的HasMap集合中;
  • 4.然后将订阅事件保存到以订阅者为key,订阅者所有订阅事件类型为value的HasMap集合中。

2.2 反注册事件

EventBus通过下面的方法注销事件:

EventBus.getDefault().unregister(this);

进入unregister()看看:

  public synchronized void unregister(Object subscriber) {
  		//根据当前注册类对象获得对应事件类型集合
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
        	//遍历,释放当前subscriber的Subscription
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);//移除typesBySubscriber中的某个注册类对象的事件类型集合
        }
    }

注销给定事件类型的订阅者,就是释放不需要用到的订阅者数据,来到unsubscribeByEventType()

   private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
   		//得到事件类型的Subscription集合
        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);
                //如果subscription的订阅者对象类和当前要取消注册的注册类对象一致,则移除当前Subscription
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

所以在unregister()方法中就是释放事件方法集合和事件类型集合的资源。

注销订阅者的流程:

  • 1.通过unregister()得到要注销的订阅者;
  • 2.获取该订阅者的所有订阅事件类型集合;
  • 3.遍历事件类型集合,根据事件类型获取所有订阅者集合,从集合中删除该订阅者;
  • 4.移除该注册者对应的事件类型集合的事件类型。

2.3 发送事件

EventBus通过下面的代码发送普通事件

EventBus.getDefault().post(Object event);

发送事件就是通过post()方法完成的:

  public void post(Object event) {
  		//currentPostingThreadState是一个PostingThreadState类型的本地线程ThreadLocal<PostingThreadState>
  		//PostingThreadState保存了线程队列、线程模式、事件方法等信息
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        //将当前事件添加到本地线程的事件队列中
        eventQueue.add(event);
		//isPosting默认为false
        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();//是否为主线程
            postingState.isPosting = true;
            try {
            	//遍历事件队列
                while (!eventQueue.isEmpty()) {
                	//发送单个事件,并且从事件队列中移除这个事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

所以post()方法是先将发送的事件保存到本地线程的事件队列中,然后循环出队列,将事件交给postSingleEvent()处理:

  private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;//是否找到subscription(subscription包含事件方法的信息)
        if (eventInheritance) {//是否有继承事件,默认为true,表示是否向上查找事件的父类
        	//根据当前事件,查找所有事件中当前事件类型的Class集合
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            //遍历Class集合,继续处理事件
            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 (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

这根据eventInheritance事件继承性来是否向上根据事件Class来查找所有该Class类型的事件,然后postSingleEventForEventType()进一步处理,如果找不到该事件的处理方法则发送找不到事件的处理:

   private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
        	//获取该事件类型对应的subscription集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        //如果该事件类型有对应的订阅事件
        if (subscriptions != null && !subscriptions.isEmpty()) {
        	//遍历事件方法体集合
            for (Subscription subscription : subscriptions) {
                postingState.event = event;//记录事件
                postingState.subscription = subscription;//记录subscription
                boolean aborted;
                try {
                	//最终事件处理
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                	//最后将相关状态设置为初始状态
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
            }
            return true;
        }
        return false;
    }

遍历发送该事件类型的所有subscription(subscription记录订阅事件的相关信息),也就说明发布者发布事件,能发送给对一个或多个该事件的订阅者。最后来到了postToSubscription()最终事件处理方法。

发送事件流程:

  • 1.获取当前线程事件队列,将要发送的事件添加到队列中;
  • 2.根据订阅者eventClass向上查找所有的事件类型集合eventTypes
  • 3.分别获取事件类型集合中的订阅者信息集合subscriptions,再在订阅者信息集合分别根据事件类型eventClass获取对应的订阅者信息subscription,最后去处理事件。

2.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 {
                	//如果发送事件的线程是子线程,则将事件加入主线程队列,通过Handler切换到主线程处理事件
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            //无论在哪一个线程发布事件,都先将事件加入主线程队列,通过Handler切换到主线程依次处理事件
            case MAIN_ORDERED:
                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;
        }
    }

可以看到postToSubscription()订阅者处理事件的线程模式以及发送事件的线程来判断如何处理事件,主要有两种:

  • 1.直接调用invokeSubscriber(),通过反射处理订阅事件方法;
  • 2.将事件加入消息队列,依次执行处理订阅事件的方法。

(1)在相应线程直接通过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);
        }
    }

这样发出去的事件就被订阅者的事件处理函数接收到并做相应处理。

(2)先将事件和订阅者封装成PendingPost加入enqueue()消息队列,队列在排队等待执行,这里对mainThreadPoster.enqueue(subscription, event)做进一步的分析,其他线程模式的enqueue()原理都是一样的:

interface Poster {//事件发送
	//为一个订阅发布事件排队执行
    void enqueue(Subscription subscription, Object event);
}

Poster是一个接口,实现了enqueue()方法,我们来看看mainThreadPoster的内部构造:

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

public interface MainThreadSupport {
    Poster createPoster(EventBus eventBus);
    class AndroidHandlerMainThreadSupport implements MainThreadSupport {
        private final Looper looper;
        public AndroidHandlerMainThreadSupport(Looper looper) {
            this.looper = looper;//主线程looper
        }
        @Override
        public boolean isMainThread() {
            return looper == Looper.myLooper();//是否为主线程
        }
        @Override
        public Poster createPoster(EventBus eventBus) {
            return new HandlerPoster(eventBus, looper, 10);//返回Poster实例
        }
    }
}

mainThreadPoster 由mainThreadSupport.createPoster()创建,所以mainThreadPoster是HandlerPoster的一个实现类,来看看HandlerPoster的内部实现:

public class HandlerPoster extends Handler implements Poster {
	······
    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);//主线程looper
        ······
    }

    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();
               
                //eventBus处理事件方法
                eventBus.invokeSubscriber(pendingPost);
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

HandlerPoster中enqueue()将PendingPost对象(包含事件方法等信息)保存到队列中,在handleMessage()循环遍历将消息逐个移除并交给EventBusinvokeSubscriber()处理事件

    void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        //释放PendingPost引用的资源
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {//订阅事件存在
        	//反射来执行订阅事件处理方法
            invokeSubscriber(subscription, event);
        }
    }

这里主要就是将PendingPost资源释放,并且如果事件存活,则通过反射来处理订阅事件方法。

  • mainThreadPoster.enqueue(subscription, event): 核心就是将事件加入线程队列中,然后通过Handler切换线程处理事件;
  • backgroundPoster.enqueue(subscription, event): 原理同上,先将事件加入队列,然后再移除队列处理事件,但是会通过线程池做进一步的处理;
  • asyncPoster.enqueue(subscription, event):       原理同上;

那么处理事件到这里完毕!

2.5 粘性事件

一般情况,我们使用EventBus都是先注册事件,实现事件方法处理函数,再发送事件,即先注册,后发布;但是粘性事件恰恰相反,我们可以先发送事件,然后再注册、处理事件函数;即先发布,后注册

我们先从发布粘性事件开始:

EventBus.getDefault().postSticky(Object event);

来看看发送粘性事件的内部方法postSticky()

   public void postSticky(Object event) {
        synchronized (stickyEvents) {
            stickyEvents.put(event.getClass(), event);
        }
        post(event);//发送事件
    }

这里就做了两件事,stickyEvents保存事件类型已经对应粘性事件,然后通过post()发送事件,这里的发送事件与发送普通事件一致。所以如果在发送粘性事件之前,如果有相同类型的事件订阅者,并且是非粘性的,那么订阅者依然可以接受到发送出来的粘性事件。

发送完粘性事件之后,再注册事件、实现事件处理方法。核心的注册流程还是上面的register()中的subscribe()方法,有一段粘性事件的代码没有分析:

  private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
  		······
		//如果订阅者事件处理方法sticky = true,表示该方法接收粘性事件
        if (subscriberMethod.sticky) {
        	//默认为true,表示是否向上查找该事件的所有子类
        	//需要考虑该事件类型的所有子类现有的粘性事件
            if (eventInheritance) {
                //stickyEvents发送粘性事件时,保存事件类型和对应事件
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    //当前事件类型是否与candidateEventType一致或者是其子类
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();//获得对应事件
                        //处理粘性事件
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

粘性事件的处理就是在注册EventBus的时候,遍历粘性事件stickyEvents集合,如果当前要注册的订阅事件方法是粘性的,并且该方法接收事件类型与粘性事件stickyEvents集合中的某个事件类型相同或者同类,则取出stickyEvents对应事件类型的事件,通过checkPostStickyEventToSubscription()做进一步处理

   private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
        	//事件处理
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }

最终通过postToSubscription()方法对粘性事件完成处理。这就是粘性事件的整个处理过程。

粘性事件的流程:

  • 1.发送粘性事件的时候先根据事件类型保存粘性事件,然后再和普通事件一样post()发送事件;
  • 2.在注册事件时根据事件处理方法判断sticky = true是粘性事件,如果stickyEventseventType一致则处理粘性事件,直接postToSubscription()响应处理事件。

三、总结

3.1注册事件原理

通过registere()注册一个订阅者,先获取当前订阅者所有订阅方法subscriberMethods,如果方法缓存METHOD_CACHE如果有则直接返回,没有则通过反射和注解@Subscribe注解找到方法名集合并保存到METHOD_CACHE中;然后根据订阅者的eventType将所有订阅者信息subscriptions 缓存到subscriptionsByEventType(HashMap)中,根据订阅者将订阅者的所有事件类型subscribedEvents(eventType集合)缓存到typesBySubscriber(HashMap)中。

3.2注销事件原理

通过unregister()得到要注销的订阅者,从typesBySubscriber获取该订阅者的所有订阅事件类型集合subscribedTypes;从该集合中根据事件类型eventType获取所有订阅者信息集合subscriptions,从集合中删除remove()该订阅者信息;再将typesBySubscriber对应的订阅者的事件类型集合移除remove()

3.3发送并处理事件原理

获取当前线程事件队列ThreadLocal<PostingThreadState>,将要发送的事件event添加到队列中;然后根据订阅者eventClass向上查找所有的事件类型集合eventTypes,分别获取所有的事件类型集合中的订阅者信息集合subscriptions,再在订阅者信息集合根据事件类型eventClass获取对应的订阅者信息subscription,最后去处理事件。

处理事件postToSubscription()是根据订阅事件的方法的线程模式,如果符合线程模式则直接执行invokeSubscriber()方法,用反射的原理invoke()来执行订阅事件的处理方法;如果不符合线程模式,则通过Poster类先将事件event和订阅者信息subscription封装成PendingPost加入enqueue()消息队列,队列在排队等待执行(后台线程会通过线程池pool做进一步处理),切换对应的线程后invokeSubscriber()执行订阅事件的处理函数。

3.4粘性事件原理

发送粘性事件的时候先根据事件类型保存粘性事件stickyEvents;然后再和普通事件一样post()发送事件;因为粘性事件是先发布,后注册响应事件的,所以在注册事件时sticky = true则进行粘性事件处理,如果stickyEventseventType一致则处理粘性事件,直接postToSubscription()响应处理事件。

最后概括一下: EventBus原理简单来说就是通过订阅者subscriber注册时保存订阅者的所有订阅事件类型和所有订阅者信息,发送事件时根据订阅者从缓存从得到相应的订阅者信息数据(包含subscriber和订阅方法的方法名,线程模式,事件类型,优先级,粘性等信息),通过线程模式,直接(对应线程)或间接(Poster类事件加入enqueue()消息队列,队列在排队等待执行,做进一步处理)通过反射的原理来执行订阅者的事件处理方法,注销时通过订阅者和事件类型eventType将缓存的信息移除。

点关注,不迷路


好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才。我是suming,感谢各位的支持和认可,您的点赞就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !

希望我们能成为朋友,在 Github掘金 上一起分享知识,一起共勉!