Android EventBus 源码解析:设计模式、原理与实现

目录

  • 一、概述
  • 二、 EventBus 整体架构
      1. 核心设计模式
      1. 架构概览
  • 二、 核心源码解析
      1. 注册过程分析
      • `subscribe()` 方法详解:
      1. 事件发布流程
      • 分发单个事件:
      1. 线程模式处理
      1. 订阅方法查找器(SubscriberMethodFinder)
      • 反射查找逻辑:
  • 四、 核心数据结构
      1. 主要存储结构
      1. 关键对象定义
  • 五、 性能优化设计
      1. 缓存机制
      1. 编译时索引优化(EventBus 3+)
  • 六、 线程处理实现(Poster)
      1. HandlerPoster 示例(主线程调度)
  • 七、 注意事项
      1. 及时反注册
      1. 谨慎使用粘性事件
      1. 避免过度使用
      1. 注意线程安全
      1. 混淆配置
  • 八、 总结
    • 1.设计亮点
    • 2.优势与价值

一、概述

EventBus 是一个基于 发布-订阅(Publish-Subscribe)模式 的事件总线框架,广泛应用于 Android 组件间的通信。它通过解耦组件之间的依赖关系,提升代码的可维护性和灵活性。


二、 EventBus 整体架构

1. 核心设计模式

设计模式 作用说明
观察者模式 实现事件的发布与订阅机制,核心逻辑所在
单例模式 默认提供全局唯一的 EventBus 实例
建造者模式 用于灵活配置自定义 EventBus 实例
策略模式 不同 ThreadMode 对应不同的线程调度策略

2. 架构概览

复制代码
发布者 (Publisher) → EventBus → 订阅者 (Subscriber)
      ↓                      ↓
    post(event)          @Subscribe方法

二、 核心源码解析

1. 注册过程分析

java 复制代码
// EventBus.java
public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = 
        subscriberMethodFinder.findSubscriberMethods(subscriberClass);

    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

subscribe() 方法详解:

java 复制代码
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("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) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    // 记录订阅者关注的所有事件类型
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);

    // 处理粘性事件
    if (subscriberMethod.sticky) {
        Object stickyEvent = stickyEvents.get(eventType);
        if (stickyEvent != null) {
            postToSubscription(newSubscription, stickyEvent, 
                isMainThread() && subscriberMethod.threadMode == ThreadMode.MAIN);
        }
    }
}

关键点

  • 使用 CopyOnWriteArrayList 保证并发安全。
  • 支持按优先级排序,高优先级先接收事件。
  • 粘性事件在注册后立即触发。

2. 事件发布流程

java 复制代码
public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get();
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);

    if (!postingState.isPosting) {
        postingState.isMainThread = isMainThread();
        postingState.isPosting = true;

        try {
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

分发单个事件:

java 复制代码
private void postSingleEvent(Object event, PostingThreadState postingState) {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;

    if (eventInheritance) {
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        for (Class<?> clazz : eventTypes) {
            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) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

特性支持

  • 支持事件继承:父类或接口事件也可被匹配。
  • 若无订阅者,可发送 NoSubscriberEvent 做兜底处理。

3. 线程模式处理

java 复制代码
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case MAIN_ORDERED:
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(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);
    }
}

五种线程模式

模式 描述
POSTING 在发布线程直接执行(默认)
MAIN 总是在主线程执行
MAIN_ORDERED 主线程中有序排队执行
BACKGROUND 后台线程执行(非主线程时直接调用)
ASYNC 异步线程池执行,不阻塞任何线程

4. 订阅方法查找器(SubscriberMethodFinder)

java 复制代码
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) return subscriberMethods;

    if (ignoreGeneratedIndex) {
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        subscriberMethods = findUsingInfo(subscriberClass); // 使用编译期索引
    }

    METHOD_CACHE.put(subscriberClass, subscriberMethods);
    return subscriberMethods;
}

反射查找逻辑:

java 复制代码
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    List<SubscriberMethod> subscriberMethods = new ArrayList<>();
    Class<?> clazz = subscriberClass;

    while (clazz != null) {
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                    Subscribe annotation = method.getAnnotation(Subscribe.class);
                    if (annotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        SubscriberMethod subscriberMethod = new SubscriberMethod(
                            method, eventType, annotation.threadMode(),
                            annotation.priority(), annotation.sticky()
                        );
                        subscriberMethods.add(subscriberMethod);
                    }
                }
            }
        }
        clazz = clazz.getSuperclass();
    }
    return subscriberMethods;
}

优化点

  • 跳过系统类包(java., android.),减少无效扫描。
  • 缓存结果避免重复反射。
  • 支持从父类中查找 @Subscribe 方法。

四、 核心数据结构

1. 主要存储结构

java 复制代码
public class EventBus {
    // 事件类型 → 所有订阅者的映射
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    
    // 订阅者对象 → 其订阅的所有事件类型的映射
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    
    // 粘性事件缓存:事件类型 → 最新事件实例
    private final Map<Class<?>, Object> stickyEvents;
    
    // 当前线程的发布状态(ThreadLocal)
    private final ThreadLocal<PostingThreadState> currentPostingThreadState;
}

2. 关键对象定义

java 复制代码
public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
}

public class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
}

五、 性能优化设计

1. 缓存机制

java 复制代码
// 避免重复反射
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = 
    new ConcurrentHashMap<>();

// 事件继承链缓存
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();

2. 编译时索引优化(EventBus 3+)

使用 APT 在编译阶段生成索引类,避免运行时反射开销。

java 复制代码
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX = new HashMap<>();

    static {
        putIndex(new SimpleSubscriberInfo(MainActivity.class, true, 
            new SubscriberMethodInfo[] {
                new SubscriberMethodInfo("onMessageEvent", MessageEvent.class, ThreadMode.MAIN),
                new SubscriberMethodInfo("onOtherEvent", OtherEvent.class, ThreadMode.BACKGROUND)
            }));
    }
}

💡 优势

  • 显著提升注册速度。
  • 减少冷启动耗时。
  • 更适合大型项目。

六、 线程处理实现(Poster)

1. HandlerPoster 示例(主线程调度)

java 复制代码
final static class HandlerPoster extends Handler implements Poster {
    private final PendingPostQueue queue;

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                sendMessage(obtainMessage());
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) break;
                eventBus.invokeSubscriber(pendingPost);
                
                // 控制单次处理时间,防止 ANR
                if (SystemClock.uptimeMillis() - started > maxMillisInsideHandleMessage) {
                    sendMessage(obtainMessage());
                    return;
                }
            }
        } finally {
            handlerActive = false;
        }
    }
}

设计亮点

  • 使用 Handler 将任务投递到主线程。
  • 采用 PendingPostQueue 缓冲待处理事件。
  • 限制单次处理时长,保障 UI 流畅。

|

七、 注意事项

1. 及时反注册

java 复制代码
@Override
protected void onDestroy() {
    super.onDestroy();
    EventBus.getDefault().unregister(this);
}

❗未反注册会导致内存泄漏!

2. 谨慎使用粘性事件

  • 粘性事件长期驻留内存。
  • 接收后建议手动清除:removeStickyEvent()

3. 避免过度使用

  • 过度依赖 EventBus 会使逻辑分散,难以追踪。
  • 复杂业务推荐使用 ViewModel、LiveData 或 RxJava。

4. 注意线程安全

  • 多线程环境下确保共享数据同步访问。
  • 粘性事件可能被多个线程修改。

5. 混淆配置

proguard 复制代码
-keepattributes Signature
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

八、 总结

1.设计亮点

特性 说明
优雅的 API 设计 注解驱动,register/unregister/post 三步完成通信
高效的线程切换 多种 ThreadMode 满足不同场景需求
性能优化充分 缓存 + 编译期索引大幅降低反射成本
支持事件继承 发送子类事件可通知父类订阅者
灵活配置能力 建造者模式构建自定义 EventBus 实例
内存安全管理 提供反注册机制,配合生命周期管理防泄漏

2.优势与价值

EventBus 通过精巧的设计,在保持简洁易用的同时,实现了强大的组件通信能力。其融合了多种经典设计模式,并结合 Android 平台特性做了深度优化,是 观察者模式在移动端的优秀实践范本

尽管随着 Jetpack 组件(如 LiveData、Flow)的发展,部分场景下可替代 EventBus,但在跨模块通信、松耦合广播等场景中,EventBus 依然具有不可替代的价值。

相关推荐
WAsbry37 分钟前
NFC开发系列专栏 - 第三篇:无界面NFC后台服务方案
android·程序员·架构
消失的旧时光-194342 分钟前
WebView 最佳封装模板(BaseWebActivity + WebViewHelper)
android·webview
WAsbry43 分钟前
NFC开发系列-第一篇:NFC开发基础与实战入门
android·程序员
WAsbry1 小时前
NFC开发系列 - 第二篇:NFC企业级架构设计与最佳实践
android·程序员·架构
feibafeibafeiba2 小时前
Android 14 关于imageview设置动态padding值导致图标旋转的问题
android
tangweiguo030519873 小时前
ProcessLifecycleOwner 完全指南:优雅监听应用前后台状态
android·kotlin
介一安全4 小时前
【Frida Android】基础篇15(完):Frida-Trace 基础应用——JNI 函数 Hook
android·网络安全·ida·逆向·frida
吞掉星星的鲸鱼4 小时前
android studio创建使用开发打包教程
android·ide·android studio
陈老师还在写代码4 小时前
android studio 签名打包教程
android·ide·android studio
csj504 小时前
android studio设置
android