EventBus3.0学习笔记

1public void onEvent(MessageEvent event) { 2 log(event.message); 3 } 4public void onEventMainThread(MessageEvent event) { 5 textField.setText(event.message); 6 } 7public void onEventBackgroundThread(MessageEvent event){ 8 saveToDisk(event.message); 9 }

什么是EventBus

EventBus是一个发布 / 订阅的事件总线。git地址:https://github.com/greenrobot/EventBus

笼统来讲EventBus可以分为三部分,发布者、订阅者、总线。订阅者通过总线订阅事件,发布者通过总线发布时间,因此订阅者就可以收到发布者发布的事件了。

如何使用EventBus

EventBus的使用也是很简单的,首先来看几个方法:

EventBus.getDefault().register(this);//订阅事件

EventBus.getDefault().post(object);//发布事件

EventBus.getDefault().unregister(this);//取消订阅

首先需要在oncreat里面注册EventBus,类似广播的注册,当然也需要在destory的时候取消注册。在需要发送也就是发布消息的地方调用post方法,注意里面的参数,然后在接受也就是事件处理的地方写几个方法即可。在3.0以前接收事件是这样的:

1 public void onEvent(MessageEvent event) { 2 log(event.message); 3 } 4 public void onEventMainThread(MessageEvent event) { 5 textField.setText(event.message); 6 } 7public void onEventBackgroundThread(MessageEvent event){ 8 saveToDisk(event.message); 9 }

方法必须以onEvent开头,但是3.0以后采用了注解的方式:

1 @Subscribe(threadMode = ThreadMode.MainThread) //在ui线程执行 2 public void onUserEvent(UserEvent event) { 3 } 4 @Subscribe(threadMode = ThreadMode.BackgroundThread) //在后台线程执行 5 public void onUserEvent(UserEvent event) { 6 } 7 @Subscribe(threadMode = ThreadMode.Async) //强制在后台执行 8 public void onUserEvent(UserEvent event) { 9 } 10 @Subscribe(threadMode = ThreadMode.PostThread) //默认方式, 在发送线程执行 11 public void onUserEvent(UserEvent event) { 12 }

举个栗子

1public class MainActivity extends Activity { 2 3 private final static String TAG = "EventBusTest"; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 // 1.注册事件订阅者("登录") 10 EventBus.getDefault().register(this); 11 } 12 13 @Override 14 protected void onDestroy() { 15 super.onDestroy(); 16 // 4.解除注册("注销") 17 EventBus.getDefault().unregister(this); 18 } 19 20 public void testActivity(View view){ 21 Intent intent = new Intent(this,third.class); 22 startActivity(intent); 23 } 24 25 // 3.接收方处理消息(处理数据)-- 主线程中执行 26 @Subscribe(threadMode = ThreadMode.MainThread) 27 public void onMainEventBus(MainMessage msg) { 28 Log.e(TAG, "onEventBus() handling message: " + Thread.currentThread().getName()); 29 } 30 31 // 3.接收方处理消息(处理数据)-- 后台线程或子线程中执行 32 @Subscribe(threadMode = ThreadMode.BackgroundThread) 33 public void onBackgroundEventBus(BackgroundMessage msg) { 34 Log.e(TAG, "onEventBusBackground() handling message: " + Thread.currentThread().getName()); 35 } 36 37 // 3.接收方处理消息(处理数据)-- 后台线程中执行 38 @Subscribe(threadMode = ThreadMode.Async) 39 public void onAsyncEventBus(AsyncMessage msg) { 40 Log.e(TAG, "onEventBusAsync() handling message: " + Thread.currentThread().getName()); 41 } 42 43 // 3.接收方处理消息(处理数据)-- 和发送方在同一个线程 44 @Subscribe(threadMode = ThreadMode.PostThread) 45 public void onPostEventBus(PostMessage msg) { 46 Log.e(TAG, "onEventBusPost() handling message: " + Thread.currentThread().getName()); 47 } 48}

另一个负责发布事件的类:

1public class OtherActivity extends Activity { 2 private final static String TAG = "EventBusTest"; 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.other_activity); 7 8 EventBus.getDefault().register(this); 9 10 } 11 // 3.接收方处理消息(处理数据)-- 主线程中执行 12 @Subscribe(threadMode = ThreadMode.MainThread) 13 public void onMainEventBus(MainMessage msg) { 14 Log.e(TAG, "onEventBus() handling message: " + Thread.currentThread().getName()); 15 } 16 public void btnClick(View view) { 17 switch (view.getId()) { 18 case R.id.btn1: 19 20 21 // 2.发送方发送消息 -- 发送MainMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据) 22 EventBus.getDefault().post(new MainMessage("Hello EventBus")); 23 24 break; 25 case R.id.btn2: 26 // 2.发送方发送消息 -- 发送BackgroundMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据) 27 // 注意,这里是在主线程中发送消息 28 EventBus.getDefault().post(new BackgroundMessage("Hello EventBus")); 29 break; 30 case R.id.btn3: 31 new Thread(){ 32 public void run() { 33 // 2.发送方发送消息 -- 发送AsyncMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据) 34 EventBus.getDefault().post(new AsyncMessage("Hello EventBus")); 35 }; 36 }.start(); 37 break; 38 case R.id.btn4: 39 new Thread(){ 40 public void run() { 41 // 2.发送方发送消息 -- 发送PostMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据) 42 EventBus.getDefault().post(new PostMessage("Hello EventBus")); 43 }; 44 }.start(); 45 break; 46 } 47 } 48}

用法还是很简单的,需要的可以下载demo:https://yunpan.cn/cSDavPcfvgLvY (提取码:9423)

简单源码解析

还是来简单看下源码,需要源码的可自行去git下载。

注册

register.java这个类是一个单例模式的类,按顺序我们先看他的register方法。

1/** 2 * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they 3 * are no longer interested in receiving events. 4 * <p/> 5 * Subscribers have event handling methods that must be annotated by {@link Subscribe}. 6 * The {@link Subscribe} annotation also allows configuration like {@link 7 * ThreadMode} and priority. 8 */ 9 public void register(Object subscriber) { 10 Class<?> subscriberClass = subscriber.getClass(); 11 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); 12 synchronized (this) { 13 for (SubscriberMethod subscriberMethod : subscriberMethods) { 14 subscribe(subscriber, subscriberMethod); 15 } 16 } 17 }

findSubscriberMethods方法作用就是遍历当前类里面的所有@Subscriber注解的方法。然后返回一个list,接着遍历List,调用subscribe方法订阅事件。

1// Must be called in synchronized block 2 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { 3 Class<?> eventType = subscriberMethod.eventType; 4 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); 5 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); 6 if (subscriptions == null) { 7 subscriptions = new CopyOnWriteArrayList<>(); 8 subscriptionsByEventType.put(eventType, subscriptions); 9 } else { 10 if (subscriptions.contains(newSubscription)) { 11 throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " 12 + eventType); 13 } 14 } 15 16 int size = subscriptions.size(); 17 for (int i = 0; i <= size; i++) { 18 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { 19 subscriptions.add(i, newSubscription); 20 break; 21 } 22 } 23 24 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); 25 if (subscribedEvents == null) { 26 subscribedEvents = new ArrayList<>(); 27 typesBySubscriber.put(subscriber, subscribedEvents); 28 } 29 subscribedEvents.add(eventType); 30 31 if (subscriberMethod.sticky) { 32 if (eventInheritance) { 33 // Existing sticky events of all subclasses of eventType have to be considered. 34 // Note: Iterating over all events may be inefficient with lots of sticky events, 35 // thus data structure should be changed to allow a more efficient lookup 36 // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>). 37 Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); 38 for (Map.Entry<Class<?>, Object> entry : entries) { 39 Class<?> candidateEventType = entry.getKey(); 40 if (eventType.isAssignableFrom(candidateEventType)) { 41 Object stickyEvent = entry.getValue(); 42 checkPostStickyEventToSubscription(newSubscription, stickyEvent); 43 } 44 } 45 } else { 46 Object stickyEvent = stickyEvents.get(eventType); 47 checkPostStickyEventToSubscription(newSubscription, stickyEvent); 48 } 49 } 50 }

根据subscriberMethod.eventType,去subscriptionsByEventType去查找一个CopyOnWriteArrayList<Subscription> ,如果没有则创建。

顺便把我们的传入的参数封装成了一个:Subscription(subscriber, subscriberMethod, priority);

这里的subscriptionsByEventType是个Map,key:eventType ; value:CopyOnWriteArrayList<Subscription> ; 这个Map其实就是EventBus存储方法的地方,一定要记住!

简单来讲这个方法就是把该类里面的所有@Subscriber注解的方法放进subscriptionsByEventType这个map里面,为后面事件做准备。

发送

1 /** Posts the given event to the event bus. */ 2 public void post(Object event) { 3 PostingThreadState postingState = currentPostingThreadState.get(); 4 List<Object> eventQueue = postingState.eventQueue; 5 eventQueue.add(event); 6 7 if (!postingState.isPosting) { 8 postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); 9 postingState.isPosting = true; 10 if (postingState.canceled) { 11 throw new EventBusException("Internal error. Abort state was not reset"); 12 } 13 try { 14 while (!eventQueue.isEmpty()) { 15 postSingleEvent(eventQueue.remove(0), postingState); 16 } 17 } finally { 18 postingState.isPosting = false; 19 postingState.isMainThread = false; 20 } 21 } 22 }

这个方法负责把事件发布到事件总线。currentPostingThreadState是一个ThreadLocal类型的,里面存储了PostingThreadState;PostingThreadState包含了一个eventQueue和一些标志位。把我们传入的event,保存到了当前线程中的一个变量PostingThreadState的eventQueue中。

根据isPosting为false的情况不断的调用postSingleEvent(eventQueue.remove(0), postingState)方法。

1private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { 2 Class<?> eventClass = event.getClass(); 3 boolean subscriptionFound = false; 4 if (eventInheritance) { 5 List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); 6 int countTypes = eventTypes.size(); 7 for (int h = 0; h < countTypes; h++) { 8 Class<?> clazz = eventTypes.get(h); 9 subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); 10 } 11 } else { 12 subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); 13 } 14 if (!subscriptionFound) { 15 if (logNoSubscriberMessages) { 16 Log.d(TAG, "No subscribers registered for event " + eventClass); 17 } 18 if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && 19 eventClass != SubscriberExceptionEvent.class) { 20 post(new NoSubscriberEvent(this, event)); 21 } 22 } 23 } 24private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { 25 CopyOnWriteArrayList<Subscription> subscriptions; 26 synchronized (this) { 27 subscriptions = subscriptionsByEventType.get(eventClass); 28 } 29 if (subscriptions != null && !subscriptions.isEmpty()) { 30 for (Subscription subscription : subscriptions) { 31 postingState.event = event; 32 postingState.subscription = subscription; 33 boolean aborted = false; 34 try { 35 postToSubscription(subscription, event, postingState.isMainThread); 36 aborted = postingState.canceled; 37 } finally { 38 postingState.event = null; 39 postingState.subscription = null; 40 postingState.canceled = false; 41 } 42 if (aborted) { 43 break; 44 } 45 } 46 return true; 47 } 48 return false; 49 }

根据event的Class,去得到一个List<Class<?>>;其实就是得到event当前对象的Class,以及父类和接口的Class类型,遍历所有的Class,到subscriptionsByEventType去查找subscriptions这个map与register里面的map是同一个。遍历每个subscription,依次去调用postToSubscription(subscription, event, postingState.isMainThread);

1private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { 2 switch (subscription.subscriberMethod.threadMode) { 3 case POSTING: 4 invokeSubscriber(subscription, event); 5 break; 6 case MAIN: 7 if (isMainThread) { 8 invokeSubscriber(subscription, event); 9 } else { 10 mainThreadPoster.enqueue(subscription, event); 11 } 12 break; 13 case BACKGROUND: 14 if (isMainThread) { 15 backgroundPoster.enqueue(subscription, event); 16 } else { 17 invokeSubscriber(subscription, event); 18 } 19 break; 20 case ASYNC: 21 asyncPoster.enqueue(subscription, event); 22 break; 23 default: 24 throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); 25 } 26 }

这个就是根据注解里的threadMode去判断在哪个线程执行了。

case PostThread:

1void invokeSubscriber(Subscription subscription, Object event) throws Error { 2 subscription.subscriberMethod.method.invoke(subscription.subscriber, event); 3

直接在当前线程里面执行了。

case MAIN:

1if (isMainThread) { 2 invokeSubscriber(subscription, event); 3 } else { 4 mainThreadPoster.enqueue(subscription, event); 5 }

首先去判断当前如果是UI线程,则直接调用;否则: mainThreadPoster.enqueue(subscription, event);把当前的方法加入到队列,然后直接通过handler去发送一个消息,在handler的handleMessage中,去执行我们的方法。说白了就是通过Handler去发送消息,然后执行的。

case BACKGROUND:

1 if (isMainThread) { 2 backgroundPoster.enqueue(subscription, event); 3 } else { 4 invokeSubscriber(subscription, event); 5 }

如果当前非UI线程,则直接调用;如果是UI线程,则将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用

executorService = Executors.newCachedThreadPool();。

case ASYNC:

asyncPoster.enqueue(subscription, event);

将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用;线程池与BackgroundThread用的是同一个。

这么说BackgroundThread和Async有什么区别呢?

BackgroundThread中的任务,一个接着一个去调用,中间使用了一个布尔型变量handlerActive进行的控制。

Async则会动态控制并发。

取消

1 /** Unregisters the given subscriber from all event classes. */ 2 public synchronized void unregister(Object subscriber) { 3 List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); 4 if (subscribedTypes != null) { 5 for (Class<?> eventType : subscribedTypes) { 6 unsubscribeByEventType(subscriber, eventType); 7 } 8 typesBySubscriber.remove(subscriber); 9 } else { 10 Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); 11 } 12 } 13/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ 14 private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { 15 List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); 16 if (subscriptions != null) { 17 int size = subscriptions.size(); 18 for (int i = 0; i < size; i++) { 19 Subscription subscription = subscriptions.get(i); 20 if (subscription.subscriber == subscriber) { 21 subscription.active = false; 22 subscriptions.remove(i); 23 i--; 24 size--; 25 } 26 } 27 } 28 }

Subscribe

1@Documented 2@Retention(RetentionPolicy.RUNTIME) 3@Target({ElementType.METHOD}) 4public @interface Subscribe { 5 ThreadMode threadMode() default ThreadMode.POSTING; 6 7 /** 8 * If true, delivers the most recent sticky event (posted with 9 * {@link EventBus#postSticky(Object)}) to this subscriber (if event available). 10 */ 11 boolean sticky() default false; 12 13 /** Subscriber priority to influence the order of event delivery. 14 * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before 15 * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of 16 * delivery among subscribers with different {@link ThreadMode}s! */ 17 int priority() default 0; 18}

ThreadMode threadMode() default ThreadMode.POSTING;

也就是前面说道的执行方式,主线程还是其他线程,默认是当前线程。

boolean sticky() default false;

默认为false,时间立即执行。如果为true那表示事件事件不被马上处理。

int priority() default 0;

优先级,数字越大优先级越高,默认0。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )