神刀安全网

玩懂EventBus:how to use,why use it,how it implements

EventBus使用

1.自定义事件类

public class GirlsLoadedEvent {     public List<Girl> girls; //要传递的数据     public GirlsLoadedEvent(List<Girl> girls) {         this.girls = girls;     } }

2.注册订阅者:EventBus.getDefault().register(this);,订阅者类声明订阅者方法处理事件:

public void onEvent(GirlsLoadedEvent event) { //订阅方法     girlsView.showGirls(event.girls);//事件处理逻辑 }

3.EventBus发布事件:EventBus.getDefault().post(new GirlsLoadedEvent(girlList));
4.取消某个订阅者的注册:EventBus.getDefault().unregister(this);

为什么要使用EventBus

EventBus是发布/订阅事件总线机制,基于观察者模式的发布/订阅设计模式(Publish/Subscibe),用于替代传统的Intent,Handler,Broadcast,自定义回调接口在线程间(主要是主线程与子线程),组件间(Activity,Service,Fragment)的通信(传递数据),因为使用EventBus更加简洁,请看下面例子。

例子: EventBus的简洁性

通过EventBusHandlerCallbackBroadcast四种途径将网络请求获取的响应结果传递给GirlsActivity,并更新UI界面。

玩懂EventBus:how to use,why use it,how it implements
1.png

玩懂EventBus:how to use,why use it,how it implements
2.png

GitHub源码:https://github.com/homcin/EventBusDemo
另外有一个完整App项目GitHub源码:https://github.com/homcin/Tuikan

源码分析

EventBus.getDefault().register(this)getDefault()是单例模式的方法,相当于getInstance()返回EventBus单例

public static EventBus getDefault() {         if (defaultInstance == null) {             synchronized (EventBus.class) {                 if (defaultInstance == null) {                     defaultInstance = new EventBus();                 }             }         }         return defaultInstance;     }

register()方法有多个重载:区别在于需要为订阅者设置优先级,是否粘性注册(Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky event of an event’s type is kept in memory for future access)。

public void register(Object subscriber) //常用的是这个,没有设置优先级和非粘性 public void register(Object subscriber, int priority) public void registerSticky(Object subscriber) public void registerSticky(Object subscriber) public void registerSticky(Object subscriber, int priority) //以上四个方法内部都是调用下面这个方法,非粘性的为false,没设置priority默认为0。 private synchronized void register(Object subscriber, boolean sticky, int priority) {     //订阅者类可以有多个订阅者方法:处理多个事件类型。     List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());     for (SubscriberMethod subscriberMethod : subscriberMethods) {         //对该订阅者的所有订阅者方法进行订阅,关键参数为订阅者+订阅者方法         subscribe(subscriber, subscriberMethod, sticky, priority);     } }

注册订阅者:通过工具类SubscriberMethodFinder实例的工具方法findSubscriberMethods(subscriber.getClass())找出该订阅者的所有订阅者方法存放到List<SubscriberMethod> subscriberMethods集合中,再对该集合中每个订阅者方法进行订阅subscribe(subscriber, subscriberMethod, sticky, priority);所以,register()注册订阅者本质是对该订阅者所有订阅者方法都调用subscribe()方法。

小插曲:

1. 何为订阅者方法:SubscriberMethod
订阅者类内部声明的以onEvent开头的方法,onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync这四个。例子见开头。
2. onEvent后面的MainThread有什么作用:
作用:决定该方法的执行环境,即该方法在哪个线程上执行。并用一个ThreadMode标识。
onEvent:在当前线程上执行。ThreadMode = ThreadMode.PostThread。
onEventMainThread:在主线程上执行。ThreadMode = ThreadMode.MainThread。
onEventBackgroundThread:在线程池中执行,任务单个顺序执行。ThreadMode = ThreadMode.BackgroundThread。
onEventAsync:在线程池中执行,任务并发执行。ThreadMode = ThreadMode.Async。

subscribe方法

首先是两个包装类:

final class SubscriberMethod { //订阅者方法包装类     final Method method;          //订阅者的订阅者方法     final ThreadMode threadMode;  //线程模式,决定在哪个线程上执行     final Class<?> eventType;     //自定义的事件类 }
final class Subscription {   //订阅信息包装类:唯一标识一个订阅者方法:订阅者+一个订阅者方法     final Object subscriber;                 //订阅者     final SubscriberMethod subscriberMethod; //订阅者方法     final int priority;                      //优先级 }

EventBus的两个重要HashMap成员变量

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; private final Map<Object, List<Class<?>>> typesBySubscriber;

1.一个事件类型可以有多个订阅者。即映射关系:Class<?> eventType –> List<Subscription>;
所以使用subscriptionsByEventType来保存事件类和它的所有订阅者的映射。
2.一个订阅者可以有多个订阅者方法,每个订阅者方法处理不同的事件类型,即一个订阅者可以处理多个事件类型。即映射关系:Object subscriber –> List<eventType> , 所以使用typesBySubscriber来保存订阅者和它可处理的所有事件类型的映射。

开始解读subscribe方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {     Class<?> eventType = subscriberMethod.eventType;     //PartA:1.获取该事件类型对应的所有订阅者集合List<Subscription>     CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);     Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);     if (subscriptions == null) {         subscriptions = new CopyOnWriteArrayList<Subscription>();         subscriptionsByEventType.put(eventType, subscriptions);     } else {         if (subscriptions.contains(newSubscription)) {             throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "                     + eventType);         }     }      int size = subscriptions.size();     for (int i = 0; i <= size; i++) {         if (i == size || newSubscription.priority > subscriptions.get(i).priority) {             //PartA:2.将该新的订阅者添加到该事件类型对应的所有订阅者集合List<Subscription>中             subscriptions.add(i, newSubscription);             break;         }     }      //PartB:1.获取该订阅者能处理的所有事件类型集合List<eventType>     List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);     if (subscribedEvents == null) {         subscribedEvents = new ArrayList<Class<?>>();         //PartB:2.将该事件类型加入到该订阅者能处理的所有事件类型集合List<eventType>         typesBySubscriber.put(subscriber, subscribedEvents);     }     subscribedEvents.add(eventType);  }

所以subscribe方法:就是将参数中的订阅者,订阅者方法中的事件类型分别添加到EventBus的两个重要HashMap成员变量subscriptionsByEventType和typesBySubscriber中。

第一步:EventBus.getDefault().register(this)分析结束:

register()——>该订阅者所有订阅者方法都调用subscribe()方法–>将订阅者,订阅者方法中的事件类型分别添加到EventBus的两个重要HashMap成员变量subscriptionsByEventType和typesBySubscriber中。

第二步:解读EventBus.getDefault().post(new GirlsLoadedEvent(girlList));

先看PostingThreadState类型的成员变量currentPostingThreadState

final static class PostingThreadState { //发布时线程状态类     final List<Object> eventQueue = new ArrayList<Object>(); //事件队列,关键是这个     boolean isPosting;          //是否正在发布事件中     boolean isMainThread;       //当前线程是否是主线程     Subscription subscription;  //订阅信息(订阅者+一个订阅者方法)     Object event;               //自定义事件     boolean canceled;           //是否取消了 } //EventBus的成员变量,类型是PostingThreadState,使用了ThreadLocal只是为了解决多线程对它的访问冲突。 private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {     @Override     protected PostingThreadState initialValue() {         return new PostingThreadState();     } };

分析post()方法:

public void post(Object event) {     PostingThreadState postingState = currentPostingThreadState.get();     List<Object> eventQueue = postingState.eventQueue;     //1. 将发布的事件插入到PostingThreadState的事件队列中     eventQueue.add(event);      if (!postingState.isPosting) {         postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();         postingState.isPosting = true;         if (postingState.canceled) {             throw new EventBusException("Internal error. Abort state was not reset");         }         try {             while (!eventQueue.isEmpty()) {                 //2. 循环不断地从事件队列中取出事件调用postSingleEvent。                 postSingleEvent(eventQueue.remove(0), postingState);             }         } finally {             postingState.isPosting = false;             postingState.isMainThread = false;         }     } }

也就是说可以同时发布多个事件,它先会将事件全部插入到事件队列中,再顺序从事件队列中取出事件单个执行postSingleEvent()方法。
postSingleEvent():遍历自定义事件的所有父类事件(因为自定义事件还可以继承父类事件),对所有的事件都调用如下的postSingleEventForEventType方法。一般来说,我们自定义事件没有继承,所以只对该自定义事件调用postSingleEventForEventType方法。

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {     CopyOnWriteArrayList<Subscription> subscriptions;     synchronized (this) {         /*         1. 从HashMap成员变量subscriptionsByEventType中取出该事件类型的所有订阅者集合List<Subscription>         */         subscriptions = subscriptionsByEventType.get(eventClass);     }     if (subscriptions != null && !subscriptions.isEmpty()) {         // 2. 发布该事件类型给它的所有订阅者。         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
先看下三个线程处理类。

final class HandlerPoster extends Handler {} final class BackgroundPoster implements Runnable {} class AsyncPoster implements Runnable {}  private final PendingPostQueue queue; public void enqueue(){queue.enqueue(pendingPost);}  final class PendingPost { //一个整体:一个事件+它所属的订阅者(唯一标识)     Object event;     Subscription subscription; }

首先三者内部都有一个队列成员queue,都提供enqueue方法用于插入事件(PendingPost)。
mainThreadPoster:Handler消息处理机制,sendMessaggehandleMessage,MainLooper
backgroundPoster:线程池,任务单个顺序执行。
asyncPoster:线程池,任务并发执行。
三者决定执行环境,如何处理任务都是调用eventBus.invokeSubscriber(pendingPost);

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {     //根据ThreadMode来选择哪种线程处理类来处理发布的消息。     switch (subscription.subscriberMethod.threadMode) {         case PostThread: //当前线程上处理             invokeSubscriber(subscription, event);             break;         case MainThread: //主线程上处理             if (isMainThread) {                 invokeSubscriber(subscription, event);             } else {                 mainThreadPoster.enqueue(subscription, event);             }             break;         case BackgroundThread: //后台线程上处理             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) {     invokeSubscriber(pendingPost.subscription, pendingPost.event); }  void invokeSubscriber(Subscription subscription, Object event) {     /*     关键处:反射知识,调用订阅者方法:method.invoke(subscription.subscriber, event)     订阅者是执行该订阅者方法的主调,event是执行该订阅者方法时传入的实参。     */     subscription.subscriberMethod.method.invoke(subscription.subscriber, event); }

至此,源码分析结束。
总结:
register(): 将订阅者和它所有的订阅者方法中的事件类型全部添加到EventBus的两个重要HashMap成员变量subscriptionsByEventType和typesBySubscriber中。
post()从HashMap成员变量subscriptionsByEventType中取出该事件类型的所有订阅者,利用反射调用每个订阅者中的参数为该事件类型的订阅者方法。

看源码学知识

1.设计模式:单例模式+观察者模式+建造者模式例子。建造者模式:builder()方法返回EventBusBuilder(:包含EventBus中optional的成员变量),EventBus构造器:EventBus(EventBuilder builder){将builder中的成员变量赋值给EventBus的成员变量}
2.任务处理的四种执行环境的写法。使用标志位boolean executorRunning来保证任务单个顺序交给线程池执行。
3.任务队列+任务对象池:PendingPostQueue queue + PendingPost中的List<PendingPost> pendingPostPool,减少创建任务对象的开销。
4.反射知识,调用class的方法。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 玩懂EventBus:how to use,why use it,how it implements

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址