EventBus原理解析

EventBus原理解析

一、概述

EventBus我们都知道是用来做app内部的数据通信的,可以达到很好的解耦合效果,传统的的广播或则回调方式存在着代码耦合度高,代码杂乱,不宜维护的特点,EventBus使用的是订阅者/发布者模式,代码简洁,高度解耦,这个是这个框架产品的背景原因了

二、整体架构

image

这个是官方框架的图,这个图描述的结构很清晰

Subscriber:这个是订阅者,订阅某个类型的消息比如onMessage(String src) 这个就订阅了接受src的消息,当然代码中还要写入@Subscrber注解

Publisher:这个是发布消息方,发布的消息经过EventBus处理后,回调执行订阅方的方法

三、使用步骤

1、注册与反注册
EventBus.getDefault().register(this);
//注册的方式很简单,这个代码写在需要订阅的类里面,比如Activity就可以
EventBus.getDefault().unregister(this);
//这个是反注册,这个要写在类的销毁方法内,这个和register是成对出现的
2、订阅方法
    @Subscribe(threadMode = ThreadMode.MAIN)
//这个是订阅模式,这个方法会在android的UI线程执行
//每个订阅方法只能有一个参数,发消息的时候会根据参数类型查找对应的方法
    public void onEventBusMessage(BMessage msg)
    {
        Log.i("eventbus",Thread.currentThread().getId()+":"+msg.toString());

    }
    @Subscribe(threadMode = ThreadMode.ASYNC)
//这个方法会在android的子线程执行
    public void onEventBusMessageSubThread(String msg)
    {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Log.i("eventbus", "isCurrentThread:"+Looper.getMainLooper().isCurrentThread());
            Log.i("eventbus", "mainthread.getId:"+Looper.getMainLooper().getThread().getId());
        }
        Log.i("eventbus",Thread.currentThread().getId()+":"+msg);

    }
3、发送消息
//发送了一个String 类型的消息
EventBus.getDefault().post("subthread");
GameTestActivity.BMessage message=new GameTestActivity.BMessage();
message.code=2;
message.msg="ss";
//发送了一个BMessage 类型的消息
EventBus.getDefault().post(message);
4、执行结果

image

我们通过日志可以看到,准确的执行了

四、原理分析

1、整体执行流程

1、注册

将注册的那个目标类里面的订阅方法通过反射的方式提取出来,保存在EventBus中

2、发送消息

根据发送的消息的参数类型,在EventBus中查找对应的订阅者信息,如果找到了就执行(invoke)对应的方法

整体的原理还是比较简单的

2、详解过程
1、注册

1、

public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
//上面这个就是查找出订阅了的方法信息,然后将每个方法信息 执行订阅过程
//SubscriberMethodFinder 这个类是用来查找注册方法的类
//我们接下来看下findSubscriberMethods 做了什么

2、

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    //先调用缓存里的数据 如果有就直接返回结果
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
		//是否忽略注解索引的方式注册方法,这个是默认是false
        if (ignoreGeneratedIndex) {
            //通过反射的方式查找
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            //apt方式
            //这个方式是通过注解索引处理器的方式来注册方法,EventBus annotation processor ,
            //这个是在编译期间完成的,速度要比传统的反射方式快很多,
            //这个还需要EventBusBuild中做配置,还有配置EventBus的annotation processor
            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;
        }
    }

我们在看下findUsingInfo这个方法,这个是注解处理器的方式实现

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    //FindState的准备工作,里面会用到了复用机制有个pool
        FindState findState = prepareFindState();
    //设置findState 里面的subscriberClass 还有class 还有skipSuperClasses=false subscriberInfo=null 信息的初始化
        findState.initForSubscriber(subscriberClass);
    //下面这个while 是通过循环的方式 在自己的class以及父类的class中查找对应的注册信息
    //while 最后面有findState.moveToSuperclass() 相当于把指针移动到了父类,直到没有为止
    //当然这个可以通过Builder 中的skipSuperClasses = true 屏蔽掉
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            //subscriberInfo 这个是要配合注解处理的方式来做,默认是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();
        }
        return getMethodsAndRelease(findState);
    }

findUsingReflectionInSingleClass(findState);

这个是实际的提取处理方法,继续看

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            //通过反射获取自身的methods 数组
            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();
            //满足条件:1、是PUBLIC修饰符 2、但是不能有下面的修饰符
            //Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC 中的一种
            //Modifier 里面都是通过十六进制 并且相邻为1的方式声明数值,方便位运算
              
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                //获取方法的参数,
                Class<?>[] parameterTypes = method.getParameterTypes();
                //只有一个参数的情况下才可以,所以EventBus 不支持多参数的方法注册
                if (parameterTypes.length == 1) {
                    //获取Subscribe.class  的注解,这个做了判断 过滤出@Subscribe 的注解方法
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class );
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            //获取线程模式,这个也是注解中写的
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //设置:优先级 priority  粘性事件sticky(post 之后注册也可以收到,通过缓存实现)					//将new的SubscriberMethod 添加到findState的集合里面
                            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");
            }
        }
    }

里面有个FindState 处理反射方式 和apt方式的中间类,处理相同逻辑的类,里面包含个各种集合数据

到此为止 我们已经获得List 结果集

然后遍历这个集合

然后我们继续看下EventBus的subscribe方法

//这个方法主要是保存数据还有,供后面的查询使用
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
    	//new 一个Subscription 这个是最后的存储的结果类
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    	//subscriptionsByEventType 这个是EventBus 存储注册方法的的集合
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            //添加一个空的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) {
                //添加一个newSubscription
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
    //储存eventType 的Map集合
        subscribedEvents.add(eventType);
		//如果这个是粘性事件 就会到stickyEvents 这里去查找然后查找 然后执行注册方法
    	//这个可以实现 先发消息 后注册也可以
        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<Class>).
                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();
                        //最终会invoke到注册方法
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

上面的整个注册的逻辑就走完了,总结来说就是 查找注册了的方法 然后保存起来

2、发送消息

1、post(object)

public void post(Object event) {
    //currentPostingThreadState 保存这当前的处理状态
    //currentPostingThreadState  这个是ThreadLocal类型,
    //这个可以保证每个线程都有各自的状态 不会冲突
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);
		//没有在发送的时候才可以发
        if (!postingState.isPosting) {
            //设置状态 当前是否在主线程操作
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            //正在发消息
            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;
            }
        }
    }

那么接下来我们就看下postSingleEvent

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
    	//这个注册方法是否 查找到的 标志
        boolean subscriptionFound = false;
    	//是否会从他们的父类查找对应的注册方法 默认是true
        if (eventInheritance) {
            //这个方法就是查找 包括父类的方法和接口, 对应类型的method信息
            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);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                //如果配置了NoSubscriberEvent 没发现注册方法 就发送NoSubscriberEvent事件
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

我们接下来继续看postSingleEventForEventType

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    	
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            //根据对应的参数类型 在map中查找对应的结果value,这个结果是之前注册保存下来的
            //这个是个数组,CopyOnWriteArrayList 这个类的特点是并发的时候 读性能很高,不担心同步问题
            //因为读不会引起并发问题
            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;
    }
//这个方法是根据threadModel 线程模式来不同的执行
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                //这个isMainThread 代表发送消息是不是在主线程,如果是就直接执行就可以了,
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    //如果不是 就mainThreadPoster执行
                    mainThreadPoster.enqueue(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);
        }
    }

主要有2个重要的类

1、HandlerPoster

切换到主线程的HandlerPoster,这个其实是个Handler,初始化的时候在EventBus中 参数是Looper.getMainLooper()的,可以用来把子线程的操作 发送到 在主线程执行
这个类里面还有个队列,达到按照先进先处理的顺序 完成

如下:

final class HandlerPoster extends Handler {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    void enqueue(Subscription subscription, Object event) {
        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;
                        }
                    }
                }
                //最终会执行注册的方法,现在已经是ui线程了
                eventBus.invokeSubscriber(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;
        }
    }
}
2、AsyncPoster

里面有异步的队列 执行处理,最终是调用了线程池getExecutorService().execute(this) 执行线程的

最后在run方法中执行了invokeSubscriber方法

class AsyncPoster implements Runnable {
	
    private final PendingPostQueue queue;
    private final EventBus eventBus;

    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);
        eventBus.getExecutorService().execute(this);
    }

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

}

那么我们看下eventBus.invokeSubscriber,这个就是最后的执行反射执行注册方法的地方了

 void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            invokeSubscriber(subscription, event);
        }
    }
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);
        }
    }

五、总结

EventBus的整体逻辑并不复杂,逻辑很清晰

1、注册,提取注册方法 存储

2、发消息,查找对应的注册方法,然后invoke执行

在研究别人优秀框架的同时学习了优秀的设计和技术,拓宽了自己的思维,在android技术开发遇到瓶颈的时候,多学习好的框架和源码是非常好的手段和策略

水平有限,如有错误,敬请指教

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值