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

文章目录

  • 介绍
    • 优点
    • 基本用法
    • 线程模式
      • POSTING
      • MAIN
      • MAIN_ORDERED
      • BACKGROUND
      • ASYNC
    • 黏性事件
  • 源码
    • 注册
      • getDefault()
      • register
      • findSubscriberMethods
      • 小结
    • post
    • postSticky
    • unregister

介绍

img

优点

  • 简化组件之间的通信
    • 解耦事件发送者和接收者
    • 在 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 上,活动和片段通常应根据其生命周期进行注册:

     @Overridepublic void onStart() {super.onStart();EventBus.getDefault().register(this);}@Overridepublic 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的信息"));

源码

注册

getDefault()

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 和局部变量 instanceinstance = 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对象。在这个有参构造函数内部对属性进行初始化

register

public class EventBus {public void register(Object subscriber) {// 1、通过反射获取到订阅者的Class对象Class<?> subscriberClass = subscriber.getClass();// 2、通过subscriberMethodFinder对象获取订阅者所订阅事件的集合List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);synchronized (this) {// 3、遍历集合进行注册for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}}private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {// 4、获取事件类型Class<?> eventType = subscriberMethod.eventType;// 5、封装Subscription对象Subscription newSubscription = new Subscription(subscriber, subscriberMethod);// 6、通过事件类型获取该事件的订阅者集合CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);// 7、如果没有订阅者订阅该事件if (subscriptions == null) {// 创建集合,存入subscriptionsByEventType集合中subscriptions = new CopyOnWriteArrayList<>();subscriptionsByEventType.put(eventType, subscriptions);} else { // 8、如果有订阅者已经订阅了该事件// 判断这些订阅者中是否有重复订阅的现象if (subscriptions.contains(newSubscription)) {throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);}}int size = subscriptions.size();// 9、遍历该事件的所有订阅者for (int i = 0; i <= size; i++) {// 按照优先级高低进行插入,如果优先级最低,插入到集合尾部if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {subscriptions.add(i, newSubscription);break;}}// 10、获取该事件订阅者订阅的所有事件集合List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();typesBySubscriber.put(subscriber, subscribedEvents);}// 11、将该事件加入到集合中subscribedEvents.add(eventType);// 12、判断该事件是否是粘性事件if (subscriberMethod.sticky) {if (eventInheritance) { // 13、判断事件的继承性,默认是不可继承// 14、获取所有粘性事件并遍历,判断继承关系Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();for (Map.Entry<Class<?>, Object> entry : entries) {Class<?> candidateEventType = entry.getKey();if (eventType.isAssignableFrom(candidateEventType)) {Object stickyEvent = entry.getValue();// 15、调用checkPostStickyEventToSubscription方法checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}} else {Object stickyEvent = stickyEvents.get(eventType);checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}}private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {if (stickyEvent != null) {// 16、如果粘性事件不为空postToSubscription(newSubscription, stickyEvent, isMainThread());}}private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {// 17、根据threadMode的类型去选择是直接反射调用方法,还是将事件插入队列switch (subscription.subscriberMethod.threadMode) {case POSTING:invokeSubscriber(subscription, event);break;case MAIN:if (isMainThread) {// 18、通过反射的方式调用invokeSubscriber(subscription, event);} else {// 19、将粘性事件插入到队列中// 最后还是会调用EventBus.invokeSubscriber(PendingPost pendingPost)方法。mainThreadPoster.enqueue(subscription, event);}break;case MAIN_ORDERED:if (mainThreadPoster != null) {mainThreadPoster.enqueue(subscription, event);} else {// temporary: technically not correct as poster not decoupled from subscriberinvokeSubscriber(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);}}void invokeSubscriber(PendingPost pendingPost) {Object event = pendingPost.event;Subscription subscription = pendingPost.subscription;PendingPost.releasePendingPost(pendingPost);if (subscription.active) {invokeSubscriber(subscription, event);}}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);}}
}public class SubscriberMethod {final Method method; // 处理事件的Method对象final ThreadMode threadMode; //线程模型final Class<?> eventType; //事件类型final int priority; //事件优先级final boolean sticky; //是否是粘性事件String methodString;
}final class Subscription {final Object subscriber;final SubscriberMethod subscriberMethod;
}

findSubscriberMethods

class SubscriberMethodFinder {private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();private static final int POOL_SIZE = 4;private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {// 1、先从之前缓存的集合中获取List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);if (subscriberMethods != null) {// 2、如果之前缓存了,直接返回return subscriberMethods;}if (ignoreGeneratedIndex) { //ignoreGeneratedIndex一般为falsesubscriberMethods = findUsingReflection(subscriberClass);} else {// 3、获取所有订阅方法集合subscriberMethods = findUsingInfo(subscriberClass);}if (subscriberMethods.isEmpty()) {throw new EventBusException("Subscriber " + subscriberClass+ " and its super classes have no public methods with the @Subscribe annotation");} else {// 4、放入缓存集合中METHOD_CACHE.put(subscriberClass, subscriberMethods);return subscriberMethods;}}private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {// 5、从数组中获取FindState对象// 如果有直接返回,如果没有创建一个新的FindState对象FindState findState = prepareFindState();// 6、根据事件订阅者初始化findStatefindState.initForSubscriber(subscriberClass);while (findState.clazz != null) {// 7、获取subscriberInfo,初始化为nullfindState.subscriberInfo = getSubscriberInfo(findState);if (findState.subscriberInfo != null) {SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();for (SubscriberMethod subscriberMethod : array) {if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {findState.subscriberMethods.add(subscriberMethod);}}} else {// 8、通过反射的方式获取订阅者中的Method,默认情况findUsingReflectionInSingleClass(findState);}findState.moveToSuperclass();}return getMethodsAndRelease(findState);}private FindState prepareFindState() {synchronized (FIND_STATE_POOL) {for (int i = 0; i < POOL_SIZE; i++) {FindState state = FIND_STATE_POOL[i];if (state != null) {FIND_STATE_POOL[i] = null;return state;}}}return new FindState();}private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// 9、订阅者中所有声明的方法,放入数组中methods = findState.clazz.getDeclaredMethods();} catch (Throwable th) {// 10、获取订阅者中声明的public方法,设置跳过父类methods = findState.clazz.getMethods();findState.skipSuperClasses = true;}// 遍历这些方法for (Method method : methods) {// 11、获取方法的修饰符:public、private等等int modifiers = method.getModifiers();// 12、订阅方法为public同时不是abstract、staticif ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {// 13、方法参数类型数组Class<?>[] parameterTypes = method.getParameterTypes();if (parameterTypes.length == 1) {// 14、获取方法的注解Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);// 15、如果有注解if (subscribeAnnotation != null) {Class<?> eventType = parameterTypes[0];// 16、将method和eventType放入到findState进行检查if (findState.checkAdd(method, eventType)) {// 17、获取注解中的threadMode对象ThreadMode threadMode = subscribeAnnotation.threadMode();// 18、新建一个SubscriberMethod对象,同时加入到findState中findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));}}} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {String methodName = method.getDeclaringClass().getName() + "." + method.getName();throw new EventBusException("@Subscribe method " + methodName +"must have exactly 1 parameter but has " + parameterTypes.length);}} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {String methodName = method.getDeclaringClass().getName() + "." + method.getName();throw new EventBusException(methodName +" is a illegal @Subscribe method: must be public, non-static, and non-abstract");}}}// 从findState中获取订阅者所有方法并释放private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {// 获取订阅者所有订阅方法集合List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);// findState进行回收findState.recycle();synchronized (FIND_STATE_POOL) {for (int i = 0; i < POOL_SIZE; i++) {if (FIND_STATE_POOL[i] == null) {FIND_STATE_POOL[i] = findState;break;}}}// 返回集合return subscriberMethods;}
}

小结

  1. 根据单例设计模式创建一个EventBus对象,同时创建一个EventBus.Builder对象对EventBus进行初始化,其中有三个比较重要的集合和一个SubscriberMethodFinder对象。
  2. 调用register方法,首先通过反射获取到订阅者的Class对象。
  3. 通过SubscriberMethodFinder对象获取订阅者中所有订阅的事件集合,它先从缓存中获取,如果缓存中有,直接返回;如果缓存中没有,通过反射的方式去遍历订阅者内部被注解的方法,将这些方法放入到集合中进行返回。
  4. 遍历第三步获取的集合,将订阅者和事件进行绑定。
  5. 在绑定之后会判断绑定的事件是否是粘性事件,如果是粘性事件,直接调用postToSubscription方法,将之前发送的粘性事件发送给订阅者。

post

public class EventBus {...public void post(Object event) {// 1、获取当前线程的PostingThreadState,这是一个ThreadLocal对象PostingThreadState postingState = currentPostingThreadState.get();// 2、当前线程的事件集合List<Object> eventQueue = postingState.eventQueue;// 3、将要发送的事件加入到集合中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 {// 4、只要事件集合中还有事件,就一直发送while (!eventQueue.isEmpty()) {postSingleEvent(eventQueue.remove(0), postingState);}} finally {postingState.isPosting = false;postingState.isMainThread = false;}}}// currentPostingThreadState是包含了PostingThreadState的ThreadLocal对象// ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据, 并且线程之间的数据是相互独立的。// 其内部通过创建一个它包裹的泛型对象的数组,不同的线程对应不同的数组索引,每个线程通过get方法获取对应的线程数据。private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}};// 每个线程中存储的数据final static class PostingThreadState {final List<Object> eventQueue = new ArrayList<>(); // 线程的事件队列boolean isPosting; //是否正在发送中boolean isMainThread; //是否在主线程中发送Subscription subscription; //事件订阅者和订阅事件的封装Object event; //事件对象boolean canceled; //是否被取消发送}...private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {// 5、获取事件的Class对象Class<?> eventClass = event.getClass();boolean subscriptionFound = false;if (eventInheritance) { // eventInheritance一般为true// 6、 找到当前的event的所有 父类和实现的接口 的class集合List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);int countTypes = eventTypes.size();for (int h = 0; h < countTypes; h++) {Class<?> clazz = eventTypes.get(h);// 7、遍历集合发送单个事件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));}}}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()); //添加当前事件的接口classclazz = clazz.getSuperclass();// 获取当前事件的父类}eventTypesCache.put(eventClass, eventTypes);}return eventTypes;}}//循环添加当前事件的接口classstatic void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {for (Class<?> interfaceClass : interfaces) {if (!eventTypes.contains(interfaceClass)) {eventTypes.add(interfaceClass);addInterfaces(eventTypes, interfaceClass.getInterfaces());}}}private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {CopyOnWriteArrayList<Subscription> subscriptions;synchronized (this) {// 8、根据事件获取所有订阅它的订阅者subscriptions = subscriptionsByEventType.get(eventClass);}if (subscriptions != null && !subscriptions.isEmpty()) {// 9、遍历集合for (Subscription subscription : subscriptions) {postingState.event = event;postingState.subscription = subscription;boolean aborted = false;try {// 10、将事件发送给订阅者postToSubscription(subscription, event, postingState.isMainThread);aborted = postingState.canceled;} finally {// 11、重置postingStatepostingState.event = null;postingState.subscription = null;postingState.canceled = false;}if (aborted) {break;}}return true;}return false;}private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {// 12、根据订阅方法的线程模式调用订阅方法switch (subscription.subscriberMethod.threadMode) {case POSTING: //默认类型,表示发送事件操作直接调用订阅者的响应方法,不需要进行线程间的切换invokeSubscriber(subscription, event);break;case MAIN: //主线程,表示订阅者的响应方法在主线程进行接收事件if (isMainThread) { //如果发送者在主线程invokeSubscriber(subscription, event);//直接调用订阅者的响应方法} else { //如果事件的发送者不是主线程//添加到mainThreadPoster的队列中去,在主线程中调用响应方法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的队列中,在线程池中调用响应方法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);}}...
}
  1. 获取当前线程的事件集合,将要发送的事件加入到集合中。
  2. 通过循环,只要事件集合中还有事件,就一直发送。
  3. 获取事件的Class对象,找到当前的event的所有父类和实现的接口的class集合。遍历这个集合,调用发送单个事件的方法进行发送。
  4. 根据事件获取所有订阅它的订阅者集合,遍历集合,将事件发送给订阅者。
  5. 发送给订阅者时,根据订阅方法的线程模式调用订阅方法,如果需要线程切换,则切换线程进行调用;否则,直接调用。

postSticky

EventBus.getDefault().postSticky(Object event)

public class EventBus {public void postSticky(Object event) {synchronized (stickyEvents) {// 1、将事件添加到粘性事件集合中stickyEvents.put(event.getClass(), event);}// 2、发送事件post(event);}
}
  1. 将粘性事件加入到EventBus对象的粘性事件集合中,当有新的订阅者进入后,如果该订阅者订阅了该粘性事件,可以直接发送给订阅者。
  2. 将粘性事件发送给已有的事件订阅者。

unregister

EventBus.getDefault().unregister(Object subscriber)

解注册的方法。

public class EventBus {...public synchronized void unregister(Object subscriber) {// 1、获取订阅者订阅的所有事件List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);if (subscribedTypes != null) {// 2、遍历集合for (Class<?> eventType : subscribedTypes) {// 3、将该订阅者的从订阅该事件的所有订阅者集合中移除unsubscribeByEventType(subscriber, eventType);}// 4、将订阅者从集合中移除typesBySubscriber.remove(subscriber);} else {logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());}}private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {// 获取该事件的所有订阅者List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions != null) {int size = subscriptions.size();// 遍历集合for (int i = 0; i < size; i++) {Subscription subscription = subscriptions.get(i);// 将订阅者从集合中移除if (subscription.subscriber == subscriber) {subscription.active = false;subscriptions.remove(i);i--;size--;}}}}...
}

1、获取订阅者的所有订阅方法,遍历这些方法。然后拿到每个方法对应的所有订阅者集合,将订阅者从集合中移除。
2、移除订阅者中所有的订阅方法。


参考:

  1. greenrobot/EventBus(github.com)
  2. EventBus源码解析 - 掘金 (juejin.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/482203.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder

原子类 JDK提供的原子类&#xff0c;即Atomic*类有很多&#xff0c;大体可做如下分类&#xff1a; 形式类别举例Atomic*基本类型原子类AtomicInteger、AtomicLong、AtomicBooleanAtomic*Array数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArrayAtomic…

【Electron学习笔记(三)】Electron的主进程和渲染进程

Electron的主进程和渲染进程 Electron的主进程和渲染进程前言正文1、主进程2、渲染进程3、Preload 脚本3.1 在项目目录下创建 preload.js 文件3.2 在 main.js 文件下创建路径变量并将 preload.js 定义为桥梁3.3 在 preload.js 文件下使用 electron 提供的contextBridge 模块3.4…

FFmpeg一些常用的命令

官网&#xff1a;https://ffmpeg.org/ 官网下载&#xff1a;https://ffmpeg.org/download.html 官网下载源码&#xff1a;https://www.ffmpeg.org/releases/ FFmpeg 实用命令 — FFmpeg 教程 文档 一、参数 1.1 FFmpeg 常用参数 参数说明备注-i filename指定输入文件&#…

JAVA篇08 —— String类

欢迎来到我的主页&#xff1a;【一只认真写代码的程序猿】 本篇文章收录于专栏【小小爪哇】 如果这篇文章对你有帮助&#xff0c;希望点赞收藏加关注啦~ 目录 1 String概述 1.1 String特性 1.2 String常用方法 2 StringBuffer类 2.1 String与StringBuffer互转 2.2 Stri…

Flink四大基石之Time (时间语义) 的使用详解

目录 一、引言 二、Time 的分类及 EventTime 的重要性 Time 分类详述 EventTime 重要性凸显 三、Watermark 机制详解 核心原理 Watermark能解决什么问题,如何解决的? Watermark图解原理 举例 总结 多并行度的水印触发 Watermark代码演示 需求 代码演示&#xff…

LabVIEW将TXT文本转换为CSV格式(多行多列)

在LabVIEW中&#xff0c;将TXT格式的文本文件内容转换为Excel格式&#xff08;即CSV文件&#xff09;是一项常见的数据处理任务&#xff0c;适用于将以制表符、空格或其他分隔符分隔的数据格式化为可用于电子表格分析的形式。以下是将TXT文件转换为Excel&#xff08;CSV&#x…

CENet及多模态情感计算实战

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

共享售卖机语音芯片方案选型:WTN6020引领智能化交互新风尚

在共享经济蓬勃发展的今天&#xff0c;共享售卖机作为便捷购物的新形式&#xff0c;正逐步渗透到人们生活的各个角落。为了提升用户体验&#xff0c;增强设备的智能化和互动性&#xff0c;增加共享售卖机的语音功能就显得尤为重要。 共享售卖机语音方案选型&#xff1a; WTN602…

云备份实战项目

文章目录 前言一、整体项目简介二、服务端环境及功能简介三、 客户端环境及功能简介四、服务端文件管理类的实现1. 获取文件大小&#xff0c;最后一次修改时间&#xff0c;最后一次访问时间&#xff0c;文件名称&#xff0c;以及文件内容的读写等功能2. 判断文件是否存在&#…

【Linux】死锁、读写锁、自旋锁

文章目录 1. 死锁1.1 概念1.2 死锁形成的四个必要条件1.3 避免死锁 2. 读者写者问题与读写锁2.1 读者写者问题2.2 读写锁的使用2.3 读写策略 3. 自旋锁3.1 概念3.2 原理3.3 自旋锁的使用3.4 优点与缺点 1. 死锁 1.1 概念 死锁是指在⼀组进程中的各个进程均占有不会释放的资源…

通俗易懂:序列标注与命名实体识别(NER)概述及标注方法解析

目录 一、序列标注&#xff08;Sequence Tagging&#xff09;二、命名实体识别&#xff08;Named Entity Recognition&#xff0c;NER&#xff09;**命名实体识别的作用****命名实体识别的常见实体类别** &#xff1a; 三、标签类型四、序列标注的三种常见方法1. **BIO&#xf…

设计模式学习[10]---迪米特法则+外观模式

文章目录 前言1. 迪米特法则2. 外观模式2.1 原理阐述2.2 举例说明 总结 前言 之前有写到过 依赖倒置原则&#xff0c;这篇博客中涉及到的迪米特法则和外观模式更像是这个依赖倒置原则的一个拓展。 设计模式的原则嘛&#xff0c;总归还是高内聚低耦合&#xff0c;下面就来阐述…

JUnit介绍:单元测试

1、什么是单元测试 单元测试是针对最小的功能单元编写测试代码&#xff08;Java 程序最小的功能单元是方法&#xff09;单元测试就是针对单个Java方法的测试。 2、为什么要使用单元测试 确保单个方法运行正常&#xff1b; 如果修改了代码&#xff0c;只需要确保其对应的单元…

用Transformers和FastAPI快速搭建后端算法api

用Transformers和FastAPI快速搭建后端算法api 如果你对自然语言处理 (NLP, Natural Language Processing) 感兴趣&#xff0c;想要了解ChatGPT是怎么来的&#xff0c;想要搭建自己的聊天机器人&#xff0c;想要做分类、翻译、摘要等各种NLP任务&#xff0c;Huggingface的Trans…

架构师:Dubbo 服务请求失败处理的实践指南

1、简述 在分布式服务中,服务调用失败是不可避免的,可能由于网络抖动、服务不可用等原因导致。Dubbo 作为一款高性能的 RPC 框架,提供了多种机制来处理服务请求失败问题。本文将介绍如何在 Dubbo 中优雅地处理服务请求失败,并结合具体实践步骤进行讲解。 2、常见处理方式 …

shell语法(1)bash

shell是我们通过命令行与操作系统沟通的语言&#xff0c;是一种解释型语言 shell脚本可以直接在命令行中执行&#xff0c;也可以将一套逻辑组织成一个文件&#xff0c;方便复用 Linux系统中一般默认使用bash为脚本解释器 在Linux中创建一个.sh文件&#xff0c;例如vim test.sh…

探索文件系统,Python os库是你的瑞士军刀

文章目录 探索文件系统&#xff0c;Python os库是你的瑞士军刀第一部分&#xff1a;背景介绍第二部分&#xff1a;os库是什么&#xff1f;第三部分&#xff1a;如何安装os库&#xff1f;第四部分&#xff1a;简单库函数使用方法1. 获取当前工作目录2. 改变当前工作目录3. 列出目…

Paper -- 建筑物高度估计 -- 基于深度学习、图像处理和自动地理空间分析的街景图像建筑高度估算

论文题目: Building height estimation from street-view imagery using deep learning, image processing and automated geospatial analysis 中文题目: 基于深度学习、图像处理和自动地理空间分析的街景图像建筑高度估算 作者: Ala’a Al-Habashna, Ryan Murdoch 作者单位: …

FTP介绍与配置

前言&#xff1a; FTP是用来传送文件的协议。使用FTP实现远程文件传输的同时&#xff0c;还可以保证数据传输的可靠性和高效性。 介绍 FTP的应用 在企业网络中部署一台FTP服务器&#xff0c;将网络设备配置为FTP客户端&#xff0c;则可以使用FTP来备份或更新VRP文件和配置文件…

DDD领域应用理论实践分析回顾

目录 一、DDD的重要性 &#xff08;一&#xff09;拥抱互联网黑话&#xff08;抓痛点、谈愿景、搞方法论&#xff09; &#xff08;二&#xff09;DDD真的重要吗&#xff1f; 二、领域驱动设计DDD在B端营销系统的实践 &#xff08;一&#xff09;设计落地步骤 &#xff0…