EventBus源码分析-post方法和postSticky

9 篇文章 0 订阅
2 篇文章 0 订阅

1.post方法源码分析

先上源码

public void post(Object event) {
  //PostingThreadState 保存着事件队列和线程状态信息
   PostingThreadState postingState = currentPostingThreadState.get();
    //获取事假队列,并将当期事件插入事件队列
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);
 
    if (!postingState.isPosting) {
        //此处标记,当前postingState所在线程,即发送事件线程是否是主线程,这个标记与事件订阅的ThreadMode有关
        postingState.isMainThread = isMainThread();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
         //处理队列中的所有事件,
        //将所有的事情交给postSingleEvent处理,并移除该事件
          while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

postingState是一个ThreadLocal变量,每个Thread有一个,里面有一个集合eventQueue里面存储了当前线程发送的事件对象,调用post时将该线程的postingState对象取出,然后再postingState的事件队列(eventQueue)里添加当前事件,判断当前postingState是否正在发送事件,如果正在发送则不进行处理,如果没有发送则进行发送,而发送的过程其实就是开启了一个while循环,当前事件集合不空则不算取出第一个事件进行处理,处理方法就是postSingleEvent()

postSingleEvent源码

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        //发送事件的事件类型
    	Class<?> eventClass = event.getClass();
    	//订阅对象是否找到的标记
        boolean subscriptionFound = false;
    	//是否支持事件继承,默认为true,如果订阅了父类型,当发送子类型事件实也会调用其相关订阅方法
        if (eventInheritance) {
            //找到所有的父类型
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                //针对每一个类型 进行分发
                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 boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            //上一篇文章讲的,该类型的所有 订阅(Subscription)的集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            //找到该事件类型注册的所有订阅
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    //发送到订阅处理方法
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

其实总结起来就是找到,找到当前订阅事件的所有注册订阅,然后将当前订阅事件发送给所有的订阅者,postToSubscription进行的处理与上一篇一样,就会最后找到该订阅的订阅对象和订阅方法,通过反射调用该对象的订阅方法,则相当于将事件发送到了订阅者手里

2.postSticky方法

postSticky方法的源码非常简单

public void postSticky(Object event) {
        synchronized (stickyEvents) {
           	//将该粘性事件加入到粘性事件map中,留待将来的注册者注册时处理
            stickyEvents.put(event.getClass(), event);
        }
        // Should be posted after it is putted, in case the subscriber wants to remove immediately
    	//像普通事件一样发送给已经订阅的订阅者
        post(event);
    }

就是将当前粘性事件保存下来,等后面注册该粘性事件的订阅者注册时发送给他,同时将该事件像发送普通事件一样发送给之前订阅了当前事件的订阅者

总结:

  • post
    1. 找到当前线程的发布事件队列,将当前事件对象加入到队列中
    2. 如果当前线程为开始发布,则开启while循环,将队列中的所有事件发布,若已经在发布中了则不用理会
    3. 事件发布先根据当前事件类型找到其所有订阅信息(包含订阅者和订阅方法)集合,然后对集合中所有订阅信息进行事件发布
    4. 每个订阅信息的事件发布根据不同的threadMode切换到不同线程,通过反射调用订阅信息里的调用者的订阅方法
  • postSticky
    1. 将当前粘性事件保存下来,等后面注册该粘性事件的订阅者注册时发送给他
    2. 调用post发送事件
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EventBus是一个轻量级的事件发布/订阅库,可以方便地实现组件之间的通信。它可以大大简化应用程序中的消息传递,减少了代码的耦合度,从而提高了应用程序的可维护性和可扩展性。 使用EventBus,你需要在你的项目中添加EventBus库的依赖。在gradle配置文件中添加如下代码: ```groovy dependencies { implementation 'org.greenrobot:eventbus:3.2.0' } ``` 然后,你需要定义你的事件类,例如: ```java public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } } ``` 接下来,订阅者需要在其onCreate()方法中注册到EventBus中: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this); } ``` 然后,你可以在订阅者中定义事件处理方法: ```java @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } ``` 最后,当你想要发送一个事件时,你可以使用EventBuspost()方法: ```java EventBus.getDefault().post(new MessageEvent("Hello world!")); ``` 这个事件将被所有订阅者接收,并且可以在onMessageEvent()方法中处理。需要注意的是,当你不再需要接收事件时,你需要在onDestroy()方法中注销订阅者: ```java @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } ``` 这就是使用EventBus的基本方法。当然,EventBus还有很多高级用法,比如可以指定事件的优先级、自定义线程模式等等。你可以查看官方文档来了解更多信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值