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 依然具有不可替代的价值。

相关推荐
ClassOps3 小时前
源码阅读 LeakCanary
android
用户2018792831673 小时前
为啥现在 Android App 不用手动搞 MultiDex 了?
android
fouryears_234174 小时前
如何将Vue 项目转换为 Android App(使用Capacitor)
android·前端·vue.js
消失的旧时光-19434 小时前
人脸跟随 ( Channel 实现(缓存5条数据 + 2度过滤 + 平滑移动))
android·java·开发语言·kotlin
小王lj4 小时前
画三角形报错bad_Alloc 原因,回调用错
android
xhbh6664 小时前
【实战避坑】MySQL自增主键(AUTO_INCREMENT)全解:从锁机制、间隙问题到分库分表替代方案
android·数据库·mysql·mysql自增主键
TimeFine5 小时前
Android 通过Dialog实现全屏
android
用户2018792831675 小时前
Android Input 的 “快递双车道”:为什么要用 Pair Socket?
android
ajassi20006 小时前
开源 java android app 开发(十八)最新编译器Android Studio 2025.1.3.7
android·java·开源