EventBus3.0源码解析

EventBus是一个事件发布/订阅总线,有效适用于Android系统平台。

EventBus优点

  • 组件之间的通信更加简单
  • 事件的发送者和接受者之间充分解耦
  • 非常好的运用在Activitys、Fragments和后台线程
  • 避免复杂和易出错的依赖性和生命周期问题
  • 代码更加简单

EventBus个人总结

register:通过反射或apt方式获取当前订阅者的所有订阅方法
post:根据发送的订阅事件,获取到指定订阅者,再根据threadMode类型,去指定线程中执行订阅方法
unregister:取消当前订阅者订阅

EventBus3.0配置使用请戳这里

源码解析

register注册

EventBus.getDefault().register(this);

getDefault方法

public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

EvnetBus是单例对象,采用双重校验方式,防止多线程并发问题。在EvnetBus构造函数中初始化EventBusBuilder对象(通过建造者模式进行创建的),主要初始化存放订阅者、订阅方法、订阅事件的Map和Poster及一些状态信息

register方法

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

subscriber: Activity或Fragment对象,就是后边所说的订阅者
subscriberClass:订阅者的Class对象
subscriberMethodFinder:获取或查找订阅者Method的对象
subscriberMethods:存放订阅者中订阅方法的列表

这里就是把订阅者订阅的方法找出来,并保存到subscriberMethods集合中,再通过循环的方式,把订阅者和订阅者中的订阅方法封装到subscriptionsByEventType中

findSubscriberMethods方法

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //先缓存获取订阅者的订阅方法
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        /**
         * ignoreGeneratedIndex 为true则表明用反射生成 subscriberMethods
         * false则使用apt获取 subscriberMethods(默认false)
         */
        if (ignoreGeneratedIndex) {
            //通过反射获取subscriberMethods
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            //如果没有配置MyEventBusIndex,依然会通过反射获取subscriberMethods
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        //注册了EvnetBus的订阅者,就必须有订阅方法,否则就会这个报错
        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;
        }
    }

METHOD_CACHE: ConcurrentHashMap采用分段锁的设计,存放的是订阅者和订阅者中的订阅方法列表
即key:订阅者的Class对象,value:订阅者中的订阅方法列表
ignoreGeneratedIndex:默认是false

这里就是获取到订阅者中的所有订阅方法,如果缓存中有则从缓存中取,没有则通过反射或apt方式获取到所有订阅方法

findUsingInfo方法

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //从FindState池中获取FindState对象
        FindState findState = prepareFindState();
        //初始化FindState对象
        findState.initForSubscriber(subscriberClass);
        //while循环查找订阅方法
        while (findState.clazz != null) {
            //如果没有配置MyEventBusIndex,则subscriberInfo为null
            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 {
                //如果没有配置MyEventBusIndex,则通过反射查找订阅方法
                findUsingReflectionInSingleClass(findState);
            }
            //进入父类继续查找订阅方法
            findState.moveToSuperclass();
        }
        //回收FindState,并返回订阅者的订阅方法列表
        return getMethodsAndRelease(findState);
    }

subscriberClass:订阅者的Class对象
findState:保存订阅者及订阅方法的信息

先判断是否配置了MyEventBusIndex,没有则通过反射查找当前类的订阅方法,然后再进入父类继续查找订阅方法,把查找到的所有订阅方法封装到FindState类的subscriberMethods集合中,最后回收FindState

prepareFindState方法

private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();
    } 

先初始化大小为4的FindState数组,通过循环从数组中拿到不为空的FindState对象,进行回收利用,如果全为空,则创建对象。

getMethodsAndRelease方法

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

从FindState中拿到订阅者的订阅方法,并返回,再把使用过的FindState对象进行回收

疑问?
prepareFindState和getMethodsAndRelease方法配合使用,定义了FindState大小为4的数组,但是感觉只会用到FindState[0],其他感觉不会用到?

findUsingReflectionInSingleClass方法
通过反射来查找订阅方法

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            //getMethods只能拿到public方法(包括继承的类或接口的方法)
            //getDeclaredMethods方法能拿到所有(包括接口但不包括继承的方法)方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {
            //获取订阅方法的类型
            int modifiers = method.getModifiers();
            //是public且非static、abstract、BRIDGE、SYNTHETIC方法则进入
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                //获取订阅方法内的参数
                Class<?>[] parameterTypes = method.getParameterTypes();
                //只有一个参数的进入
                if (parameterTypes.length == 1) {
                    //查找包含Subscribe注解
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    //如果不为空,则说明是订阅者订阅了EvnetBus的方法,否则就不是
                    if (subscribeAnnotation != null) {
                        //获取订阅方法内第一个参数的字节码对象
                        Class<?> eventType = parameterTypes[0];
                        //校验是否添加该方法
                        if (findState.checkAdd(method, eventType)) {
                            //获取注解上定义的线程模式
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //把订阅方法、订阅方法内参数的class对象、threeadMode线程模式、优先级大小、是否接受粘性事件封装到SubscriberMethod对象中,并添加到存放订阅方法的List中
                            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)) {
                //提示订阅方法必须是public修饰的
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

1:通过反射来获取订阅者中的所有方法
2:根据方法的类型、参数、注解找到所有订阅方法
3:把订阅方法、订阅方法内参数的class对象、threeadMode线程模式、优先级大小、是否接受粘性事件封装到SubscriberMethod对象中,并添加到FindState对象的subscriberMethods列表中

checkAdd方法

boolean checkAdd(Method method, Class<?> eventType) {
            //两层检查:第一层根据EventType,第二层根据签名
            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) {
                return true;
            } else {
                if (existing instanceof Method) {
                    //如果父类和子类订阅方法和参数相同返回false,否则返回true
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    //放置FindState对象,使其再次不进入if (existing instanceof Method)方法
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }

注意
当报IllegalStateException错误时,则优先查看父类和子类是否有相同的订阅方法和参数

checkAddWithMethodSignature方法

private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());
            //methodKey:方法的名字+'>'+参数的名字
            String methodKey = methodKeyBuilder.toString();
            //获取方法所在类的字节码对象
            Class<?> methodClass = method.getDeclaringClass();
            //如果key之前存在,则返回之前存放的value
            Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
            //如果传递过来的methodClass是父类,methodClassOld是子类,则进入else
            //如果父类和子类订阅方法和参数相同则肯定会进入else,否则进入if
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                return true;
            } else {
                subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            }
        }

isAssignableFrom:用来判断一个类Class1和另一个类Class2是否相同或是Class2类的超类或接口

1:第一次检查根据eventType参数类的字节码,判断是否存在,不存在则返回true,并添加此订阅方法,存在则进入第二次检查
2:第二次检查则先把前一次保存的方法名和方法内的参数类名组合成key,把方法所在的类名定义成value存放到HashMap中
—>如果methodClassOld等于null或者methodClassOld和methodClass相等或者是methodClass的父类则进入,否则进入到else并抛异常。
—>如果父类和子类订阅方法和参数相同则肯定会进入else抛异常,否则进入if添加订阅方法

目的:如果父类订阅了此方法,子类就不需要再重新订阅了,因为可以直接继承过来

以上就是findSubscriberMethods方法内所做的操作,主要作用就是拿到订阅者中所有订阅方法

register方法

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

subscribe方法

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //获取订阅方法中参数的Class对象
        Class<?> eventType = subscriberMethod.eventType;
        //创建一个Subscription来保存订阅者和订阅方法
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //根据订阅方法的事件类型获取特定的Subscription
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);

        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            //如果不为null,并且包含了这个newSubscription,那么说明该subscriber已经注册了该事件,抛出异常
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        //根据优先级把订阅事件添加到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<>();
            //把订阅者、事件放进HashMap中
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        //添加订阅方法内参数的Class对象
        subscribedEvents.add(eventType);

        //粘性事件处理
        .....省略.....
    }

newSubscription:保存订阅者和订阅方法
subscriptionsByEventType: Key是订阅方法中事件类型的Class对象,value是存放Subscription的集合,在Subscription中保存着订阅者和订阅方法
typesBySubscriber:用于取消注册EventBus的HashMap,Key是订阅者对象,value是存放订阅方法内参数的Class对象的列表

总结
1:通过反射找到订阅者内的所有订阅方法
2:把订阅者和订阅方法封装Subscription对象里,再添加到CopyOnWriteArrayList集合中,再以订阅方法中事件类型的Class对象为key,CopyOnWriteArrayList为value存放到subscriptionsByEventType->HashMap中(发送事件时就是从此Map中取)
3:根据优先级把订阅事件添加到CopyOnWriteArrayList集合中
4:添加用于取消注册EvnetBus的HashMap

post发布订阅事件

public void post(Object event) {
        //获取当前线程的PostingThreadState,即每个线程维护一份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) {//是否取消post
                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对象,PostingThreadState对象主要是封装当前线程的一些状态、订阅者、订阅事件等信息
第二步:从PostingThreadState中获取事件队列,再把当前事件插入到事件队列中
第三步:循环处理队列中的所有事件

第9行是先判断事件是否正在发布,如果正在发布则isPosting为true,if语句就不会进入,但post方法会进入,然后把事件添加到事件队列中,此时第17行还是会循环处理队列中添加的事件

postSingleEvent方法

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        //默认eventInheritance=true
        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 {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        .....省略.....
    }

这里是先从缓存中获取待发送事件类型的列表,用列表的目的就是要包括当前事件的父类和接口类,然后通过循环的方法发送事件

lookupAllEventTypes方法

private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
        synchronized (eventTypesCache) {
            //先从缓存中获取需要发送事件类型的列表,这个列表包括当前事件类及父类和接口
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
            if (eventTypes == null) {
                eventTypes = new ArrayList<>();
                Class<?> clazz = eventClass;
                while (clazz != null) {
                    eventTypes.add(clazz);
                    //添加发送事件类型的接口类
                    addInterfaces(eventTypes, clazz.getInterfaces());
                    //添加发送事件类型的父类,知道Object类则停止
                    clazz = clazz.getSuperclass();
                }
                //放到缓存中
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }

这里先从缓存中获取事件类型列表,如果没有,则创建,然后添加当前事件类型、事件类型的接口类、事件类型的父类,最后再放到eventTypesCache->HashMap中。

发送事件类型(包括事件类型的父类和实现的接口类)举例

public interface Animal {
}

public class DogEvent {
}

public class MessageEvent extends DogEvent implements Animal {
    private String name;

    public MessageEvent(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

发送事件

mBtn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new MessageEvent("hao"));
            }
        });

订阅方法

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void messageEvent(MessageEvent evet){
        Log.d("message", "MessageEvent");
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void dogEvent(DogEvent evet){
        Log.d("message", "DogEvent");
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void animal(Animal evet){
        Log.d("message", "Animal");
    }

打印结果
12-11 10:23:01.530 5509-5509/com.cn.liuyz.javademo D/message: MessageEvent
12-11 10:23:01.531 5509-5509/com.cn.liuyz.javademo D/message: Animal
12-11 10:23:01.531 5509-5509/com.cn.liuyz.javademo D/message: DogEvent

这里所说的发送事件类型的列表,就包括Animal、DogEvent、MessageEvent、Object,当只发送MessageEvent事件时,列表中这几个订阅事件都可以接受到。

postSingleEventForEventType方法

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

subscriptionsByEventType中Key是订阅方法中事件类型的Class对象,value是存放Subscription的集合,在Subscription中保存着订阅者和订阅方法。

postToSubscription方法

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

先获取订阅方法运行的线程,再各个处理,如MAIN主线程,是则通过反射invoke调用订阅方法,否则利用Handler机制,把信息发送到主线程,再通过反射invoke调用订阅方法。
HandlerPoster、BackgroundPoster、AsyncPoster稍后再讲解…

BACKGROUND和ASYNC区别
BACKGROUND中的任务是一个接着一个去调用,使用executorRunning布尔值进行控制(顺序执行)
Async中的任务会立即获取空闲线程或者直接创建线程去执行(并发执行)
都是使用Executors.newCachedThreadPool()线程池

invokeSubscriber方法

void invokeSubscriber(Subscription subscription, Object event) {
        try {
            //通过反射调用订阅方法
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        }
        .....省略.....
    }

发送事件到此就结束了

总结
第一步:获取一个与当前线程相关联的PostingThreadState对象
第二步:把事件添加到PostingThreadState的事件列表中,再以循环的方式发送事件
第三步:利用反射的方式调用订阅者的订阅方法

unregister取消注册

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

unsubscribeByEventType方法

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        //根据事件类型从subscriptionsByEventType中获取相应的 subscriptions 集合
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            //遍历订阅者集合,从subscriptions中移除订阅者
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

总结
第一步:获取订阅者内的所有订阅事件的集合
第二步:根据订阅事件获取所有的订阅了该事件的订阅者集合,再从订阅者集合中移除当前订阅者
第三步:从typesBySubscriber中移除订阅者

粘性事件的发送及接收源码分析

粘性事件与一般的事件不同,粘性事件是先发送出去,然后让后面注册的订阅者能够收到该事件。粘性事件的发送是通过postSticky方法进行发送

发送粘性事件

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

订阅方法

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 100)
    public void sticky1(MessageEvent event) {
        Log.d("message", "");
    }

threadMode:订阅方法运行的线程
sticky:是否为粘性事件
priority:优先级,优先级越高,在调用时越先调用

postSticky方法

public void postSticky(Object event) {
        synchronized (stickyEvents) {
            stickyEvents.put(event.getClass(), event);
        }
        post(event);
    }

先把事件放到stickyEvents->HashMap中
再调用post方法,就和正常发送一样了,但不会有相应的订阅者内的订阅方法来响应

注意
stickyEvents中Key是订阅事件的Class对象,如果在不同的类中发送的粘性事件对象相同,则会覆盖之前的,保存最后一次发送的粘性事件对象,如果在不同的类中发送的粘性事件对象不同,则不受影响,都可以接受到。

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        .....省略.....
        //sticky从订阅方法的注解上获取
        if (subscriberMethod.sticky) {
            if (eventInheritance) {//默认true
                //获取所有粘性事件
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    //获取Map中的key即订阅事件的Class对象
                    Class<?> candidateEventType = entry.getKey();
                     //如果订阅者订阅的事件类型与当前的粘性事件类型相同,则把该事件分发给这个订阅者
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        //获取Map中的value即订阅事件类型对象
                        Object stickyEvent = entry.getValue();
                        //发送事件
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                //根据eventType,从stickyEvents集合中获取指定的事件类型对象
                Object stickyEvent = stickyEvents.get(eventType);
                //发送事件
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }
checkPostStickyEventToSubscription方法
    private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            //执行订阅方法
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }

Poster源码解析

HandlerPoster

构造方法

protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        //在主线程运行处理消息的最大时间,默认是10毫秒
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        //PendingPostQueue队列
        queue = new PendingPostQueue();
    }

enqueue方法

public void enqueue(Subscription subscription, Object event) {
        //将Subscription和订阅事件封装到PendingPost中
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            //添加到队列中
            queue.enqueue(pendingPost);
            //如果handlerActive为true,说明正在处理消息,我们只需要加入队列即可
            if (!handlerActive) {
                handlerActive = true;
                //发送消息
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

handleMessage方法

public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                //循环从队列中取出pendingPost
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        //为null时,再次取一下
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            //循环停止
                            handlerActive = false;
                            return;
                        }
                    }
                }
                //利用反射调用订阅方法
                eventBus.invokeSubscriber(pendingPost);
                //判断消息处理时间,大于10毫秒则抛异常
                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;
        }
    }

HandlerPoster的执行是顺序一个一个执行的
都注释的很清楚了,就不总结了。

BackgroundPoster

BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        //PendingPostQueue队列
        queue = new PendingPostQueue();
    }
public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            //添加到队列中
            queue.enqueue(pendingPost);
            //如果executorRunning为true,说明正在处理消息,我们只需要加入队列即可
            if (!executorRunning) {
                executorRunning = true;
                //获取Executors.newCachedThreadPool()缓存线程池并执行(调用run方法)
                eventBus.getExecutorService().execute(this);
            }
        }
    }
public void run() {
        try {
            try {
                while (true) {
                    //循环从队列中取出pendingPost,最大等待时间是10毫秒
                    PendingPost pendingPost = queue.poll(1000);
                    .....省略.....
                    eventBus.invokeSubscriber(pendingPost);
                }
                .....省略.....
            }
        }
    }

BackgroundPoster的执行是顺序一个一个执行的

AsyncPoster

AsyncPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }
public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        //添加到队列中
        queue.enqueue(pendingPost);
        //获取Executors.newCachedThreadPool()缓存线程池并执行(调用run方法);
        eventBus.getExecutorService().execute(this);
    }

这里是立即执行,如果有缓存线程则获取缓存线程调用run方法,如果没有缓存线程则创建线程调用run方法,AsyncPoster的执行是并发的

public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

其他方法

EventBus.getDefault().cancelEventDelivery(event) ;//优先级高的订阅者可以终止事件往下传递
EventBus.getDefault().isRegistered(this);//判断当前类是否注册了EventBus
EventBus.getDefault().removeAllStickyEvents();//删除所有粘性事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值