详细讲解Android框架EventBus

        工欲善其事,必先利其器。要想非常好的将EventBus运用到项目的实践当中去,就必须能够对其框架的内部的机制有很好的理解。So,就有了下面的系列文章。

         整个的EventBus框架分为两个包,22个类。包名分别是de.greenrobot.event与de.greenrobot.event.util。很显然,一个是框架的核心代码包,一个是其辅助作用的包,即工具类的集合。在de.greenrobot.event框架下一共有14个类,按照功能,可以大致分为这样几个方面:1)主进程与后台进程处理事件的真正工作者,包括:AsyncPoster、BackgroundPoster以及HandlerPoster。2)围绕整个框架的主题所涉及到的几个类,包括:EventBus、EventBusBuilder以及EventBusException。3)围绕订阅事件的对象Subscriber所需要的几个类,包括:NoSubscriberEvent、SubscriberExceptionEvent、SubscriberMethod以及SubscriberMethod。4)事件消息与事件消息队列相关的类,包括:PendingPost与PendingPostQueue。6)工具包不再一一说明。

      

        1、详细讲解主进程与后台进程处理事件的真正工作者

AsyncPoster实际上是异步的处理事件消息的队列,在这个类中,所涉及到两个成员变量,分别是事件消息队列与主框架Bus。AsyncPoster实现Runnable的接口,其工作正如其Run方法中所体现的那样,从消息队列中取出消息,交给Bus进行触发。同时它还有一个将事件投放到事件队列中的功能。核心方法如下:

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

BackgroundPoster整体代码与AsyncPoster非常的类似,但是与其不同的是其run方法中是一个while的循环,在当前的事件队列不是空的情况下,会一直从事件的队列中获取事件并且交给Bus去触发。核心代码如下:

 try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
HandlerPoster与上面两个同样是处理事件,但类型不同,HandlerPoster对应的是Handler。其余的功能上与BackgroundPoster保持一致。核心代码如下:

 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);
                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、详细讲解围绕整个框架的主题所涉及到的几个类

EventBus无疑是一个核心,首先从构造函数来分析与猜测其大致的功能:1)初始化一个基于事件类型所分类的订阅对象的HashMap 2)通过订阅者所划分的类型的HashMap  3)初始化一个粘性事件所对应的一个ConcurrentHashMap 4)初始化三个任务的执行的对象 5)初始化搜索订阅者方法的对象。 6)相关的日志与异常所对应的布尔值的初始化 7)初始化一个线程池。

其中我们需要关注的方法是subscribe ,也就是具体体现了一个事件是如何被订阅的,其核心代码如下
     

//订阅方法的事件类型
        Class<?> eventType = subscriberMethod.eventType;
        //通过类型获取订阅的列表
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        //基于参数创建一个新的订阅的对象
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<Subscription>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
        // subscriberMethod.method.setAccessible(true);
        //强制方法必须是public的类型
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
        	//综合优先级与相应的索引进行对应的排序
            if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        //通过订阅者得到当前的类型的列表
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<Class<?>>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        //将订阅方法中的事件类型添加进去
        subscribedEvents.add(eventType);

        if (sticky) {
            Object stickyEvent;
            synchronized (stickyEvents) {
                stickyEvent = stickyEvents.get(eventType);
            }
            if (stickyEvent != null) {
                // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
                // --> Strange corner case, which we don't take care of here.
                postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
            }
        }
还需要关心的是一个方法是如何被触发的,其方法是invokeSubscriber,对应的核心代码如下:

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

本质上是利用反射机制 Method与invoke

EventBusBuilder可以说是EventBus的配置项,具体的配置属性可以从其成员变量中看出 1、创建默认线程池  2、相关日志打印的开关 3、部分Class 允许跳过检测

3、详细讲解围绕订阅事件的对象Subscriber所需要的几个类

SubscriberExceptionEvent正如其名称一样,它是由EventBus所提交的一个事件,当异常出现在一个订阅者的事件的处理中。

SubscriberMethod对应的是触发订阅者的方法,同样从其构造方法来猜测其大致的功能,1)成员变量Method的赋值  2)当前的事件在哪种线程的模式先工作,线程模式ThreadMode具体可以看见代码的注释。 3)触发的事件的类型

SubscriberMethodFinder的功能是寻找订阅者的哪些方法会被触发,还是用到了较多的反射机制,核心代码如下:

Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                String methodName = method.getName();
                //是否是方法名以onEvent开头
                if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
                    int modifiers = method.getModifiers();
                    //强制性是public的类型  并且不允许在忽略的类型的方法的里面
                    if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                        Class<?>[] parameterTypes = method.getParameterTypes();
                        if (parameterTypes.length == 1) {
                        	//去除其中的参数
                        	//通过函数名 决定在哪种线程中进行运行
                            String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
                            ThreadMode threadMode;
                            if (modifierString.length() == 0) {
                                threadMode = ThreadMode.PostThread;
                            } else if (modifierString.equals("MainThread")) {
                                threadMode = ThreadMode.MainThread;
                            } else if (modifierString.equals("BackgroundThread")) {
                                threadMode = ThreadMode.BackgroundThread;
                            } else if (modifierString.equals("Async")) {
                                threadMode = ThreadMode.Async;
                            } else {
                                if (skipMethodVerificationForClasses.containsKey(clazz)) {
                                    continue;
                                } else {
                                    throw new EventBusException("Illegal onEvent method, check for typos: " + method);
                                }
                            }
                            Class<?> eventType = parameterTypes[0];
                            methodKeyBuilder.setLength(0);
                            methodKeyBuilder.append(methodName);
                            methodKeyBuilder.append('>').append(eventType.getName());
                            String methodKey = methodKeyBuilder.toString();
                            if (eventTypesFound.add(methodKey)) {
                                // Only add if not already found in a sub class
                                subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
                            }
                        }
                    } else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
                        Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
                                + methodName);
                    }
                }
            }
            clazz = clazz.getSuperclass();

Subscription是EventBus中的重要的数据模型,其维护的变量主要是包括:订阅者、订阅者的触发的方法以及触发的优先级。


      OK,相信介绍到这里相信童鞋们对EventBus这种框架的代码以及有一定的了解了吧!希望这篇文章对大家有帮助,这样也不辜负我的文字啦~







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值