源码解析-EventBus

  • 示例使用
  • 时序图
  • 源码解读

EventBus 使用

  • 官网定义:EventBus 是一个使用 Java 写的观察者模式,解耦的Android开源库。EventBus 只需要几行代码即可解耦简化代码,加快开发速度。

    使用:

  1. 定义 events

    Events 就是个 POJO 类

public class MessageEvent {

    public final String message;

    public MessageEvent(String message) {
        this.message = message;
    }
}
  1. 准备 subscribers

    需要

    ```java

    // This method will be called when a MessageEvent is posted (in the UI thread for Toast)

    @Subscribe(threadMode = ThreadMode.MAIN)

    public void onMessageEvent(MessageEvent event) {

    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();

    }

// This method will be called when a SomeOtherEvent is posted

@Subscribe

public void handleSomethingElse(SomeOtherEvent event) {

doSomethingWith(event);

}

```

subscribers 需要注册

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}
  1. 发送 evnets
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

在需要接收时间的地方,通过 @Subscribe

Github:https://github.com/greenrobot/EventBus

官网:http://greenrobot.org/eventbus/

时序图

源码解析

  • 思路:通过 EventBus.gerDefault().register(this),把当前的 Activity 或者 Fragment 和通过反射拿到在其中用 @Subscribe 修饰的方法保存到相关的容器中,通过 post() 方法携带 Event ,从容器中取出相关的 subscribe 和方法,通过反射调用该方法,把消息分发到目标 subscribe 。在 Activity 或 Fragment 生命周期销毁的时候,通过 unRegister() 把 subscribe 从容器中移除,去掉订阅者模式,防止内存泄漏。
  • 相关类
    • interface Poster:接口,唯一方法 enqueue(), 加入队列的。
    • HandlerPoster: 切换到 UI 线程的 Poster 实现类,内部通过一个链表存储消息,通过 Handler 把消息切换到 UI 线程,从而实现更新 UI 线程
    • BackgroundPoster: 后台执行 Event 的 Poster 实现类
    • AsyncPoster:与 BackgroudPoster 类似
    • PendingPostQueue: 存储 PendingPost 的链表
    • Subscription: 订阅对象,有 subscriber 和 subscribeMethod 构成
    • SubscriberMethod: subscriber 中的接收方法,有 方法名称 ,threadMode, priority, 是否是粘性, eventType
    • PostingThreadState:保存在 ThreadLocal 中,主要存储 event 的相关信息, 是否在主线程,订阅者信息,是否取消,是否已发送。
    • MainThreadSupport: 切换到 UI 线程用的,配合 HandlerPoster 一起使用。
    • SubscriberInfo:Base class for generated index classes created by annotation processing
  • 从使用的入口开始

    注册:EventBus.getDefault().register(this)

发送消息:EventBus.getDefault().post(event)

  • 发送消息一般调用 post() 方法,然后把定义的 Event 发送出去,看下 post() 方法源码

    public void post(Object event) {
        // ThreadLocal 中获取变量 postingState.
        PostingThreadState postingState = currentPostingThreadState.get();
        // 从 postingState 中拿到 ArrayList
        List<Object> eventQueue = postingState.eventQueue;
        // 把当前 event 加入到 ArrayList 中
        eventQueue.add(event);
        // 是否已发送,在主线程
        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                // ArrayList 不为 Null , 循环取出来数据,通过 postSingleEvent() 发送。
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                // Arraylist 中所有的消息都发送完成,设置 isPosting 和 isMainThread 为 false。
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

    从 ThreadLocal 中拿到 PostingThreadState ,然后把消息放入的到变量 ArrayList 中,然后判断 postingState 的状态,是否处于发送状态,不在发送状态的话,进入条件判断然后遍历 ArrayList 调用 postSingleEvent() 方法把 event 发送。看下 postSingleEvent() 源码

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        // 订阅者信息是否能找到
        boolean subscriptionFound = false;
        // 通过 EventBusBilder 传入的, 默认为 true
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                // 进入到了 postSingleEventForEventType() 方法
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

    在方法 postSingleEvent() 中,通过成员变量 eventInheritance (表示是否要向上查找事件的父类) 来判断,默认为 true ,所以进入 if 中,lookupAllEventTypes() 方法会通过递归的方式进行查找所有父类事件并存到 List 中。然后通过遍历调用 postSingleEventForEventType() 方法进行处理

    看下 lookupAllEventTypes() 源码,其中 addInterfaces() 通过递归拿到全部的父类事件。

    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());
                    clazz = clazz.getSuperclass();
                }
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }

    addInterfaces() 源码,通过递归调用方法,查找所有的父类事件并加入到 List 中

    static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        for (Class<?> interfaceClass : interfaces) {
            if (!eventTypes.contains(interfaceClass)) {
                eventTypes.add(interfaceClass);
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }

    看下 postSingleEventForEventType() 源码。成员变量 subscriptionsByEventType 是一个 Map<Class<?>, CopyOnWriteArrayList<Subscription>>, 通过成员变量拿到 subscriptions ,然后遍历该列表,调用 postToSubscription() 方法

    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        // 线程安全的ArrayList 保存订阅者信息
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            // 根据 clz 获取该类的订阅者信息列表
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            //遍历订阅者信息列表
            for (Subscription subscription : subscriptions) {
                //设置 postingState 的状态
                postingState.event = event;
                postingState.subscription = subscription;
                // 是否可以取消,默认不可取消
                boolean aborted = false;
                try {
                    // 传入订阅者信息,event, 是否在主线程
                    postToSubscription(subscription, event, postingState.isMainThread);
                    // postingState.canceled 默认是 false 。表示不可取消
                    aborted = postingState.canceled;
                } finally {
                    //postingState 恢复成默认状态。
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

    进入 postToSubscription() 源码,根据订阅者在注册的时候存入的 threadModeevent 分发到不同的线程中。根据 threadMode 不同,可以分为 POSTING, MAIN, MAIN_ORDERED, BACKGROUND, ASYNC。 变量 mainThreadPoster 其实是 HandlerPoster ,把消息发送到 UI 线程的。

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:// 订阅者与 event 在相同线程
                invokeSubscriber(subscription, event);
                break;
            case MAIN:// UI 线程
                // event 是在 UI 线程,则直接通过反射调用。
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    // event 不在 UI 线程,则加入队列,通过 Handler 切换到 UI 线程
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED://UI线程,按照顺序发送消息
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND://
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC://订阅者单独一个线程,不同于发送线程和UI线程。
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

    invokeSubscriber() 方法,通过反射执行订阅者的订阅方法

    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.getDefault().unregister(this);

原文地址:https://www.cnblogs.com/liyiran/p/9172989.html

时间: 2024-10-06 07:06:24

源码解析-EventBus的相关文章

[EventBus源码解析] EventBus.register 方法详述

前情概要 在上一篇中,介绍了EventBus的基本使用方法,以及一部分进阶技巧.本篇及以后的几篇blog将会集中解析EventBus.java,看看作者是如何优雅地实现这个看似简单的事件分发/接收机制. 本篇概述 剖析register的过程,let's get started! 方法签名 完整的register方法签名如下,我们通常调用的register(this)其实最终调用到的register(this, false, 0),另外,使用registerSticky(this)进行调用,其实最

Android EventBus3.0使用及源码解析

叨了个叨 最近因为换工作的一些琐事搞的我一个头两个大,也没怎么去学新东西,实在是有些愧疚.新项目用到了EventBus3.0,原来只是听说EventBus的鼎鼎大名,一直没仔细研究过.趁着周末有些时间,研究下代码,也算没有虚度光阴. EventBus GitHub : https://github.com/greenrobot/EventBus EventBus3.0简介 EventBus是greenrobot出品的一个用于Android中事件发布/订阅的库.以前传递对象可能通过接口.广播.文件

Android 开源项目源码解析(第二期)

Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations 源码解析 SlidingMenu 源码解析 Cling 源码解析 BaseAdapterHelper 源码分析 Side Menu.Android 源码解析 DiscreteSeekBar 源码解析 CalendarListView 源码解析 PagerSlidingTabStrip 源码解析 公共

Android事件总线(二)EventBus3.0源码解析

相关文章 Android事件总线(一)EventBus3.0用法全解析 前言 上一篇我们讲到了EventBus3.0的用法,这一篇我们来讲一下EventBus3.0的源码以及它的利与弊. 1.构造函数 当我们要调用EventBus的功能时,比如注册或者发送事件,总会调用EventBus.getDefault()来获取EventBus实例: public static EventBus getDefault() { if (defaultInstance == null) { synchroniz

Android EventBus源码解析, 带你深入理解EventBus

上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢? 1.概述 一般使用EventBus的组件类,类似下面这种方式: [java] view plain copy public class SampleComponent extends Fragment { @Override public vo

EventBus 源码解析

EventBus 源码解析 本文为 Android 开源项目源码解析 中 EventBus 部分项目地址:EventBus,分析的版本:ccc2771,Demo 地址:EventBus Demo分析者:Trinea,校对者:扔物线,校对状态:完成 1. 功能介绍 1.1 EventBus EventBus 是一个 Android 事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递,这里的事件可以理解为消息,本文中统一称为事件.事件传递既可用于 Android 四大组件间通讯

Android EventBus源码解析 带你深入理解EventBus

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢? 1.概述 一般使用EventBus的组件类,类似下面这种方式: public cl

65.源码解析:EventBus

1.使用 注册: public class MyBaseFragment extends Fragment { @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//注册EventBusEventBus.getDefault().register(this);} @Overridepublic void onDestroy() {super.onDestroy(

AndroidEventBus源码解析带你深入理解EventBus(转载)

AndroidEventBus源码解析带你深入理解EventBus 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢? 1.概述 一般