美文网首页Android面试题
Android SystemUI的EventBus实现原理

Android SystemUI的EventBus实现原理

作者: BossMozil | 来源:发表于2018-10-15 17:02 被阅读0次

    Android 8.1的SystemUI的recents模块实现了Eventbus,用于recents模块内通信。本文分析其代码实现原理。

    EventBus概述

       Eventbus是由greenrobot组织贡献的一个Android事件发布/订阅轻量级框架,基于观察者设计模式,通过解耦发布者和订阅者简化Android事件传递。Android SystemUI源码中的EventBus只简单的实现了事件传递,没有实现线程模型,粘性事件等,可以看作是简化版的Eventbus。

    Eventbus实现

      在SystemUI中按照如下图所示发布者/订阅者模式实现EventBus。


      EventBus的处理流程是订阅者在EventBus中register(订阅)事件,当发布者发送出事件时,EventBus根据事件查找到订阅了该事件的订阅者列表,并逐一调用订阅者的onBusEvent()事件响应函数,把事件传给订阅者处理。


    EventBus类图

    1.事件订阅

      register订阅事件最终调用到如下所示函数(这里贴出的是主要的代码)。传入的参数为subscriber的类对象,获取该类所有函数,遍历并通过函数isValidEventBusHandlerMethod判断是否为EventBus的事件响应函数(public、final类型,void返回类型和函数名以onBusEvent开头),找到响应函数后,保存到mEventTypeMap对象属性中,mEventTypeMap是个HashMap对象实例,以Event的子类对象的Class属性为key,ArrayList<EventHandler>为值。如上面的类图所示,EventHandler有类型为EventHandlerMethod的属性method,而EventHandlerMethod中属性mMethod类型为Method,用于记录订阅者的事件响应函数。

     /**
         * Registers a new subscriber.
         */
        private void registerSubscriber(Object subscriber, int priority,
                MutableBoolean hasInterprocessEventsChangedOut) {
                ... ...
       
            Class<?> subscriberType = subscriber.getClass();
                ... ...
    
            // Find all the valid event bus handler methods of the subscriber
            MutableBoolean isInterprocessEvent = new MutableBoolean(false);
            Method[] methods = subscriberType.getDeclaredMethods();
            for (Method m : methods) {
                Class<?>[] parameterTypes = m.getParameterTypes();
                isInterprocessEvent.value = false;
                if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) {
                    Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0];
                    ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType);
                    if (eventTypeHandlers == null) {
                        eventTypeHandlers = new ArrayList<>();
                        //记录事件响应函数
                        mEventTypeMap.put(eventType, eventTypeHandlers);
                    }
                    EventHandlerMethod method = new EventHandlerMethod(m, eventType);
                    EventHandler handler = new EventHandler(sub, method, priority);
                    eventTypeHandlers.add(handler);
                    subscriberMethods.add(method);
                    sortEventHandlersByPriority(eventTypeHandlers);
                }
            }
        }
        /**
         * @return whether {@param method} is a valid (normal or interprocess) event bus handler method
         */
        private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes,
                MutableBoolean isInterprocessEventOut) {
            int modifiers = method.getModifiers();
            if (Modifier.isPublic(modifiers) &&
                    Modifier.isFinal(modifiers) &&
                    method.getReturnType().equals(Void.TYPE) &&
                    parameterTypes.length == 1) {
                    ... ...
                    //METHOD_PREFIX:"onBusEvent"
              if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) &&
                                method.getName().startsWith(METHOD_PREFIX)) {
                    isInterprocessEventOut.value = false;
                    return true;
                }
            ... ...
            return false;
        }
    
    

    2.事件发送、响应

      发送事件时调用EventBus类的send()、post()、sendOnMainThread()函数,三个都函数只有一个Event类型的参数。接着会调用queueEvent() 函数,通过mEventTypeMap.get(event.getClass())获取相应的EventHandler,然后通过其中的Method类型属性对象反射调用事件响应函数。至此事件传递完成。

    private void processEvent(final EventHandler eventHandler, final Event event) {
            ... ...
            try {
              
                Object sub = eventHandler.subscriber.getReference();
                if (sub != null) {
                    //反射调用事件响应函数
                    eventHandler.method.invoke(sub, event);               
                } else {
                    Log.e(TAG, "Failed to deliver event to null subscriber");
                }
            } catch (IllegalAccessException e) {
                Log.e(TAG, "Failed to invoke method", e.getCause());
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e.getCause());
            }
        }
    

    总结

      Android SystemUI中的EventBus实现如上分析。与greenrobot组织使用注解来标识事件响应函数不同,SystemUI通过函数名前缀的方式标识事件响应函数。两者都是通过反射调用事件响应函数。有兴趣深入了解的同学可以下载SystemUI源码或者EventBus.java来进一步学习。

    相关文章

      网友评论

        本文标题:Android SystemUI的EventBus实现原理

        本文链接:https://www.haomeiwen.com/subject/zqzfzftx.html