【Android】EventBus的使用及源码分析

介绍

在这里插入图片描述

优点

  • 简化组件之间的通信
    • 解耦事件发送者和接收者
    • 在 Activity、Fragment 和后台线程中表现良好
    • 避免复杂且容易出错的依赖关系和生命周期问题
  • 让你的代码更简单
  • 很快,很小
  • 具有高级功能,如交付线程、订阅者优先级等。

基本用法

导入依赖

implementation "org.greenrobot:eventbus:3.3.1"
  1. 定义事件:
public static class MessageEvent {
   
    /* Additional fields if needed */ }
  1. 准备订阅者:声明并注释您的订阅方法,可以选择指定线程模式

    @Subscribe(threadMode = ThreadMode.MAIN)  
    public void onMessageEvent(MessageEvent event) {
         
         
        // Do something
    }
    

    注册和取消注册您的订户。例如在 Android 上,活动和片段通常应根据其生命周期进行注册:

     @Override
     public void onStart() {
         
         
         super.onStart();
         EventBus.getDefault().register(this);
     }
    
     @Override
     public void onStop() {
         
         
         super.onStop();
         EventBus.getDefault().unregister(this);
     }
    
  2. 发布活动:

 EventBus.getDefault().post(new MessageEvent());

线程模式

POSTING

  • 特点:订阅者在发布事件的同一线程中被调用。
  • 优点:开销最小,避免了线程切换。
  • 适用场景:已知任务简单且快速完成,不依赖主线程。
  • 注意:长时间任务可能阻塞发布线程(如是主线程,会导致UI卡顿)。
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
   
   
    log(event.message); // 快速返回的简单任务
}

MAIN

  • 特点:

    • 订阅者在主线程(UI线程)中被调用
    • 如果发布线程为主线程,则同步调用(与 POSTING 类似)
  • 适用场景:UI更新或需要在主线程完成的轻量任务。

  • 注意:避免执行耗时任务,否则会阻塞主线程,导致卡顿。

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
   
   
    textView.setText(event.message); // 更新UI
}

MAIN_ORDERED

  • 特点:
    1. 在主线程中执行。
    2. 按顺序执行:事件会一个接一个地处理,不会乱序。
  • 适用场景:依赖特定执行顺序的UI更新逻辑。
  • 注意:与 MAIN 类似,避免耗时任务,确保任务快速返回。
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMessageEvent(String event) {
   
   
    Log.d("EventBus", "Event received: " + event); // 按顺序更新UI
}

BACKGROUND

  • 特点:
    • 如果发布线程为主线程,事件处理方法会切换到后台线程。
    • 如果发布线程是非主线程,事件处理方法直接在发布线程中执行。
  • 适用场景:后台任务,如数据库存储、文件操作。
  • 注意:快速返回,避免阻塞后台线程。
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event) {
   
   
    saveToDisk(event.message); // 后台存储操作
}

ASYNC

  • 特点:事件处理程序始终在独立线程中调用,与发布线程或主线程完全分离。
  • 适用场景:耗时操作,如网络请求、复杂计算。
  • 注意:避免触发大量异步任务,防止线程池耗尽资源。
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event) {
   
   
    backend.send(event.message); // 异步网络请求
}

黏性事件

发送事件之后再订阅也能收到该事件

@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
public void onMessageEvent(MessageEvent messageEvent) {
   
   
    tv.setText(messageEvent.getMessage());
}
EventBus.getDefault().postSticky(new MessageEvent("SecondActivity的信息"));

源码

构造

public class EventBus {
   
   

    // 静态变量,存储唯一的 EventBus 实例
    // 使用 volatile 关键字,确保多线程环境下变量的可见性和防止指令重排
    static volatile EventBus defaultInstance;

    public static EventBus getDefault() {
   
   
        // 将静态变量 defaultInstance 赋值给局部变量 instance,减少对主内存的访问
        EventBus instance = defaultInstance;

        // 第一次检查,避免不必要的同步开销
        if (instance == null) {
   
   
            // 如果实例未被初始化,进入同步块
            synchronized (EventBus.class) {
   
   
                // 再次将 defaultInstance 的值赋给 instance(看这个时候defaultInstance为不为空)
                instance = EventBus.defaultInstance;

                // 第二次检查,确保实例仍未被初始化(双重检查锁定)
                if (instance == null) {
   
   
                    // 创建新的 EventBus 实例并赋值给 defaultInstance 和局部变量 instance
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }
}
public EventBus() {
   
   
    this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

建造者模式

EventBus(EventBusBuilder builder) {
   
   
    //日志
    logger = builder.getLogger();
    //这个集合可以根据事件类型获取订阅者
    //key:事件类型,value:订阅该事件的订阅者集合
    subscriptionsByEventType = new HashMap<>();
    //订阅者所订阅的事件集合
    //key:订阅者,value:该订阅者订阅的事件集合
    typesBySubscriber = new HashMap<>();
    //粘性事件集合
    //key:事件Class对象,value:事件对象
    stickyEvents = new ConcurrentHashMap<>();
    //Android主线程处理事件
    mainThreadSupport = builder.getMainThreadSupport();
    mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
    //Background事件发送者
    backgroundPoster = new BackgroundPoster(this);
    //异步事件发送者
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    //订阅者订阅事件查找对象
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                                                        builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    logSubscriberExceptions = builder.logSubscriberExceptions;
    logNoSubscriberMessages = builder.logNoSubscriberMessages;
    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    throwSubscriberException = builder.throwSubscriberException;
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
}

这个方法内部首先通过单例模式创建一个EventBus对象,在创建EventBus时最终会调用它的有参构造函数,传入一个EventBus.Builder对象。在这个有参构造函数内部对属性进行初始化

注册

public void register(Object subscriber) {
   
   
    // 1、通过反射获取到订阅者的Class对象
    Class<?> subscriberClass = subscriber.getClass();
    // 2、获取订阅者所订阅事件的集合(1)
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
   
   
        // 3、遍历集合进行注册
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
   
   
            // 遍历订阅者的订阅方法来完成订阅者的订阅操作
            subscribe(subscriber, subscriberMethod);
        }
    }
}

获取订阅者所订阅事件集合

public class SubscriberMethod {
   
   
    final Method method; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值