EventBus 源码分析

来源:互联网 发布:淘宝怎么看在线人数 编辑:程序博客网 时间:2024/05/22 01:53

EventBus 源码分析

先上github 地址:eventbus

首先,说说Eventbus 是什么,能干什么

其为android中的事件总线框架,用于在app内不同模块间通信消息传递的框架。简单的说,就是一个地方发送一个广播,在注册了该广播的地方接受到广播(在对应的函数中)。

怎么使用?

1.需要创建一个类,该类对应着一类事件。(相当于广播中的,意图过滤器中的条件)

class MyEvent{} // 代表一类事件。 即一类的广播。

2.在需要相应的类中,进行注册。(对应的要在该类销毁的时候,进行注销操作)

EventBus.getDefault().register(this);// 注册该类为接受者EventBus.getDefault().unregister(this);// 注销该类。

3.在注册的类中,添加对应接受事件的函数。比如

public void onEvent(MyEvent event) {// TODO 在接收到该事件时,我们要进行的相应处理。}

4.发送一个事件。也可以理解为发送一个广播。

EventBus.getDefault().post(new MyEvent());//  发送的MyEvent对象,会被注册了该事件的方法中得到回调。

简单的用法就是这些了。

eventbus 源码

我们就从其暴露给我们的接口来一步步看起源码。

首先看从getDefault方法开始。

// 这里可以看到一个典型的创建的单例public static EventBus getDefault() {        if (defaultInstance == null) {            synchronized (EventBus.class) {                if (defaultInstance == null) {                    defaultInstance = new EventBus();                }            }        }        return defaultInstance;  }

在eventbus的构造函数中

EventBus(EventBusBuilder builder) {        subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>();//   key 为所以Event的class,value为          该注册了该event的所以类。        typesBySubscriber = new HashMap<Object, List<Class<?>>>();   // key为注册event的类,value为该类中的所有event的class。  以上两         个集合非常重要,会频繁出现在下面的分析中。        stickyEvents = new ConcurrentHashMap<Class<?>, Object>(); // 保存粘性事件的集合。 key为event.class  value为该class对应的对象实例。        // 以上三个map用来存放我们注册的事件相关的数据。        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);        backgroundPoster = new BackgroundPoster(this);        asyncPoster = new AsyncPoster(this);        // 以上三个类,用来实现在不同线程中回调onEvent()函数。第一个为在通过handler实现主线程的回调。 后两个都是runnable的子类,是实现在子         线程中回调。        subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses);// 该类为一个功能性辅助类,在该         类中主要实现在一个类中,查找出所以得 onEvent方法。        // 以下为以下简单的配置信息设置。        logSubscriberExceptions = builder.logSubscriberExceptions;        logNoSubscriberMessages = builder.logNoSubscriberMessages;        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;        throwSubscriberException = builder.throwSubscriberException;        eventInheritance = builder.eventInheritance;        executorService = builder.executorService;    }

然后我们在看一下register(Object subscriber)方法,都会调用一个方法。

//subscriber 为注册的类,sticky 是否是粘性事件,priority为优先级 ,会影响存入map的顺序,进而影响回调的顺序。private synchronized void register(Object subscriber, boolean sticky, int priority) {         List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());        for (SubscriberMethod subscriberMethod : subscriberMethods) {            subscribe(subscriber, subscriberMethod, sticky, priority);        }    }

首先,我们看到首先调用了SubscriberMethodFinder的findSubscriberMethods方法。给类做的事情就是 把 订阅了事件的类中的所有的onEvent回调函数给返回出去。

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {        String key = subscriberClass.getName();        List<SubscriberMethod> subscriberMethods;         synchronized (methodCache) {            subscriberMethods = methodCache.get(key);// methodCache 为一个static变量,注册的类为key,以该类中所有注册函数的list为value,相当于一级缓存。将所有的注册类中的注册方法保存下来。避免多次遍历类中方法的操作。        }        if (subscriberMethods != null) {            return subscriberMethods; // 如果已经处理过该类,直接使用缓存下来的数据返回。        }        subscriberMethods = new ArrayList<SubscriberMethod>();        Class<?> clazz = subscriberClass;        HashSet<String> eventTypesFound = new HashSet<String>(); // 保存已经添加的方法和该方法的参数拼接的字符串,用于防止重复添加。        StringBuilder methodKeyBuilder = new StringBuilder();        while (clazz != null) { // 循环遍历该类,以及其父类            String name = clazz.getName();            //忽略掉系统中的类            if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {                // Skip system classes, this just degrades performance                break;            }            // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)            Method[] methods = clazz.getDeclaredMethods();            for (Method method : methods) {                String methodName = method.getName();                if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { // 以OnEvent开始的方法                    int modifiers = method.getModifiers();                            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //访问修饰符判断 public且非Ignone方法                        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 SubscriberMethod类为封装了一个类中接收函数信息的封装类。其中包含了方法method、该方法需要回调的线程threadmode、对应的事件类型eventtype。                                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(); // 获取父类的class,继续循环        }        if (subscriberMethods.isEmpty()) {            throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "                    + ON_EVENT_METHOD_NAME);        } else {            synchronized (methodCache) {                methodCache.put(key, subscriberMethods);//将该类中的所有对应的响应方法的集合缓存下来。            }            return subscriberMethods;        }    }

然后,遍历得到集合,调用subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority)方法。该方法 主要功能就是为了将我们在EventBus 构造函数中创建的subscriptionsByEventType、typesBySubscriber和stickyEvents这三个集合,将对应的数据保存在他们中。前面已经说过他们对应保存的数据,这里就不重复了。

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {        Class<?> eventType = subscriberMethod.eventType; // 事件的对应的class        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); // 先从集合中获取以前保存的。        Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);// subscription 类为对接受事件的类的包装类,里面包含 subscribe        r 就是我们register(Object o)时传入的this。一般就是activity或fragment。subscribermethod 就是该类中的onevent方法的封装,priority        if (subscriptions == null) {//如果为空,代表第一次处理该event。创建list,并且将list添加到subscriptionsByEventType中。            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)        //将newSubscription按照优先级添加到中。        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;            }        }// 到此,subscriptionsByEventType这个集合填充完毕。        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);//同样的,先将这个类中之前event.class的集合取出。        if (subscribedEvents == null) {  // 如果为空,代表是第一次,创建list集合,并且将其放到typesBySubscriber这个map中            subscribedEvents = new ArrayList<Class<?>>();            typesBySubscriber.put(subscriber, subscribedEvents);        }        subscribedEvents.add(eventType);// 将event加到刚才创建的list中。        if (sticky) {  // 是否是粘性事件。如果不是的话,register方法到此就结束了。如果是注册的是粘性事件监听,就会在注册的时候,执行以下代码。            Object stickyEvent;            synchronized (stickyEvents) {                stickyEvent = stickyEvents.get(eventType); // 该集合中的stickyEvent是在postSticky(Object o)的时候,添加到集合中的。所以所谓的粘性事件就是在这类                                                           注册粘性事件监听之前,就已经被post过的事件,在注册的时候会被直接调用,并将之前的Object作为参数传入。            }            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()); // 这里是post粘性事件。该方法是post事件的核心方                法。之后在分析post模块的时候,会继续分析。            }        }    }

到这里,我们就算走完了全部register的流程。我们现在回顾一下注册所做的事情。其实,最主要的事情就是将注册的类(比如activity)中的对应的onevent回调回调函数(比如 OnEvent(MyEvent myevent)),以及其参数,通过自己定义的包装类,保存到相应的集合之中(subscriptionsByEventType,typesBySubscriber)。

然后,我们再看一看,我们是如何post一个事件是如何实现的。

public void post(Object event) {        PostingThreadState postingState = currentPostingThreadState.get();//获得在和该线程有关的postingState对象。        List<Object> eventQueue = postingState.eventQueue;   // 将event添加到postingState中的list中。        eventQueue.add(event);        if (!postingState.isPosting) { //根据postingState的状态,设置一下相应的状态。            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()) { // 将eventQueue中所有的对象post出去。                    postSingleEvent(eventQueue.remove(0), postingState);                }            } finally {                postingState.isPosting = false;                postingState.isMainThread = false;            }        }    }

首先,我们先看一下PostingThreadState这个类。它是EventBus的内部类。其中主要是保存事件的一些信息,就是一个bean对象。这里需要特别关注一下currentPostingThreadState这个对象。它是ThreadLocal的实例。ThreadLocal可以理解一个用于在不同线程中保存数据的一个容器。比如你在主线程中添加了一条数据,又在子线程中添加了一条数据,然后,当你在主线程中去get的时候,拿到的就是你之前在主线程中保存的数据,如果你在子线程中去get,那么拿到的就是你在子线程中保存的数据。对于具体如何实现的,有兴趣的同学可以自己去研究研究,其中有用到很巧妙的算法。

然后我们在看看postSingleEvent(Object event, PostingThreadState postingState)方法.

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {        Class<?> eventClass = event.getClass(); // event对应的class        boolean subscriptionFound = false;          if (eventInheritance) {   // 代表是否将event的父类,也进行处理。            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);  // 在该方法中,通过循环,将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);        } }

然后,其都会调用postSingleEventForEventType方法,返回的boolean代表是否存在对应的注册者类。

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {        CopyOnWriteArrayList<Subscription> subscriptions;        synchronized (this) { // 这里我们看到,我们通过eventClass从subscriptionsByEventType中拿到我们之间在注册的时候添加进去的该event的所对应的注册者的集合。            subscriptions = subscriptionsByEventType.get(eventClass);        }        if (subscriptions != null && !subscriptions.isEmpty()) {            for (Subscription subscription : subscriptions) {// 遍历该event 所有的注册者                postingState.event = event;                postingState.subscription = subscription;                boolean aborted = false;  // 将信息保存到postingState对象中                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;    }

在这里然后调用 postToSubscription方法。该方法在之前就有遇到过。实在register时,对于粘性事件我们调用了该方法。现在我们就来看看到底该方法干了什么。

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {        switch (subscription.subscriberMethod.threadMode) {            case PostThread:                invokeSubscriber(subscription, event);                break;            case MainThread:                if (isMainThread) {                    invokeSubscriber(subscription, event);                } else {                    mainThreadPoster.enqueue(subscription, event);                }                break;            case BackgroundThread:                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);        }    }

我们看到了,主要是通过区分subscription.subscriberMethod.threadMode的类型,以及当前方法执行的线程(也就是post方法调用的时候的线程),来调用不同方法。

这里主要有四种方式。 一种是invokeSubscriber(subscription, event) (其实最后调用的都是这个方法,不过是在不同线程中调用而已)代表在当前线程中调用。第二种 mainThreadPoster.enqueue(subscription, event),在主线程中调用。第三种 backgroundPoster.enqueue(subscription, event) 会在子线程中调用,而且该线程是维护了一个队列,依次处理所有的加入的数据。第四种是asyncPoster.enqueue(subscription, event)会开辟新的子线程在其中执行。

正如我刚才说的,其实最后调用的都是invokeSubscriber(Subscription subscription, Object event)这个方法。 只是通过在不同线程中调用,来实现在不同线程中回调。

void invokeSubscriber(Subscription subscription, Object event) {      subscription.subscriberMethod.method.invoke(subscription.subscriber, event);     // 实现功能的就是该方法,通过反射调用该方法。      .......    }

现在我们来看看如何实现在不同线程中调用该方法。如果还记得的话,我们在eventbus的构造函数中,曾经创建过三个对象

mainThreadPoster,backgroundPoster,asyncPoster这三个对象,对应于不同线程。

首先,mainThreadPoster其实就是一个handler,而且是主线程中的handler,所以其对应的handleMessage方法会在主线程中执行。

首先调用了enqueue(Subscription subscription, Object event)方法。

首先,我们看PendingPost类,该也是一个封装event和subscription的类,但是不同的是其中包含一个pendingPostPool的存储集合,该集合里面添加进去的是我们之前创建过的PendingPost的对象。其作用是复用以前创建过的对象,减少对象创建的开销。

static void releasePendingPost(PendingPost pendingPost) {        pendingPost.event = null;        pendingPost.subscription = null;        pendingPost.next = null;       // 将使用完毕的PendingPost中的数据清空        synchronized (pendingPostPool) {            // Don't let the pool grow indefinitely            if (pendingPostPool.size() < 10000) {                pendingPostPool.add(pendingPost); 添加到集合中            }        }    }

在我们需要一个新的PendingPost的对象的时候

static PendingPost obtainPendingPost(Subscription subscription, Object event) {        synchronized (pendingPostPool) {            int size = pendingPostPool.size();            if (size > 0) { //如果集合中有不用的PendingPost,将其取出,并且将对应的数据添加到其中。                PendingPost pendingPost = pendingPostPool.remove(size - 1);                pendingPost.event = event;                pendingPost.subscription = subscription;                pendingPost.next = null;                return pendingPost;            }        }        return new PendingPost(event, subscription);    }

然后,回到enqueue方法中,

void enqueue(Subscription subscription, Object event) {        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); // 获得封装了subscription和event的pendingpost对象        synchronized (this) {            queue.enqueue(pendingPost); // 将其添加到自己定义的队列中            if (!handlerActive) {                handlerActive = true;                if (!sendMessage(obtainMessage())) { // 调用sendmessage方法发送一个空消息,会调用handler的handlemessage方法中。                    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 = queue.poll();  //从队列中取出在enqueue中添加的数据。                if (pendingPost == null) {                    synchronized (this) {                        // Check again, this time in synchronized                        pendingPost = queue.poll();                        if (pendingPost == null) {                            handlerActive = false;                            return;                        }                    }                }  // 以上部分是为了判断队列是否为空的考虑线程安全的方法。                eventBus.invokeSubscriber(pendingPost); // 这里,就是实现真正功能的代码。我们看到,它又回到了EventBus类中,只不过,它是在主线程中调用的。因为这是在主线程的handler的handlemessage方法中。                long timeInMethod = SystemClock.uptimeMillis() - started; //又获取了一次系统时间,通过时间差,来控制循环。(当队列中数据好多时,才会用到)                if (timeInMethod >= maxMillisInsideHandleMessage) {                       if (!sendMessage(obtainMessage())) {  //如果此次循环已经超过规定时间,发送一个消息,会重新调用handlemessage方法。                        throw new EventBusException("Could not send handler message");                    }                    rescheduled = true;                    return;                }            }        } finally {            handlerActive = rescheduled;        }    }

我们再回到eventbus中看看invokeSubscriber方法

void invokeSubscriber(PendingPost pendingPost) {        Object event = pendingPost.event;        Subscription subscription = pendingPost.subscription; // 将封装在PendingPost中的数据取出来。        PendingPost.releasePendingPost(pendingPost);// 会将PendingPost对象中的数据清空,放到其内部的集合中,以便将来再用。        if (subscription.active) {            invokeSubscriber(subscription, event);// 该方法,以前已经分析过了,就是通过反射回调到相应的方法中,完成post的实现。        }    }

到这里,我们就看完了在主线程中实现回调的实现了。对于BackgroundPoster和AsyncPoster其实现是类似的,唯一的区别就是其是实现Runnable接口,其是运行在子线程中的。其中也是先将数据添加到一个队列中,然后再其run方法中调用eventBus.invokeSubscriber(pendingPost)方法。这两个的区别就是 一个线程安全,一个线程不安全。

到此。post方法我们也算分析完毕了。对于unregister()方法,如果前面的都看懂了,那么unregister就很简单了,就是将之前register时保存到集合中的数据删除掉就好了。这里就不再累赘了。相信大家都可以轻松看懂的。

0 0
原创粉丝点击