(一)介绍

1,EvenetBus是一种发布-订阅事件总线.

代码简洁,开销小,并很好的实现了发送者和接收者的解耦.(是一种观察者模式)

2,三要素:

Event:事件Publisher:发布者,可以在任意线程发布事件Subscrible:订阅者,

3,通常情况下安卓下数据的传递有下面几种方法:

3.1.通过intent传递,包括显式意图和隐式意图,广播(Broadcast)和服务都能通过Intent传递传递的数据类型包括8大基本数据类型 实现Parcelable或Serializable接口的类型 以及集合数组类型3.2.静态变量传递 在工具类下 声明一个Object类型的静态变量 在A中将要传递的值,在B中通过这个静态变量取出来3.3.通过handle在不同的线程中传递Object类型的数据3.4.通过构造方法传递Object类型的数据3.5.通过SharedPreferences传递八大基本数据类型3.6.通过ContentProvider在进程间共享数据3.7.通过aidl在进程进程传递数据3.8.通过流(本地文件)传递八大基本数据类型和实现Serializable接口的数据类型3.9.通过基类中的属性或者方法属性: 基类公有属性 在某个子类中赋值 其他子类中都能使用方法: 子类调用父类的某个方法给父类某个属性赋值 另外一个子类通过父类的另一个公有方法获取这个值(这个方法把值返回)

(二)基本使用

先订阅,后发布

1,添加依赖

compile 'org.greenrobot:eventbus:3.1.1'

2,注册事件

public class MessageEvent { private String message; public MessageEvent(String message){ this.message = message; } public String getMessage(){ return message; }}

3,在接受消息的代码

//注册成为订阅者 EventBus.getDefault().register(this); @Override protected void onDestroy() { super.onDestroy(); //解除注册 EventBus.getDefault().unregister(this); } //订阅方法,当接收到事件的时候,会调用该方法 @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(MessageEvent messageEvent){ Log.e("date","receive it"); Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show(); }

4,在发送消息的地方

EventBus.getDefault().post(new MessageEvent("从fragment将数据传递到activity22222222"));

先发布,再订阅,黏性事件

5,在接受消息的代码

//注册成为订阅者 EventBus.getDefault().register(this); @Override protected void onDestroy() { super.onDestroy(); //解除注册 EventBus.getDefault().unregister(this); } //订阅方法,当接收到事件的时候,会调用该方法 @Subscribe(threadMode = ThreadMode.MAIN,stick = true) public void onEvent(MessageEvent messageEvent){ Log.e("date","receive it"); Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show(); }

6,在发送消息的地方

EventBus.getDefault().postSticky(new MessageEvent("从fragment将数据传递到activity22222222"));

(三)四个订阅方法

onEvent:

如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。

onEventMainThread:

如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。

onEventBackground:

如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。

onEventAsync:

使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync。

(四)源码解析

可以看到,发布者(Publisher)使用post()方法将Event发送到Event Bus,而后Event Bus自动将Event发送到多个订阅者(Subcriber)。这里需要注意两个地方:

(1)一个发布者可以对应多个订阅者。

(2)3.0以前订阅者的订阅方法为onEvent()、onEventMainThread()、onEventBackgroundThread()和onEventAsync()。在Event Bus3.0之后统一采用注解@Subscribe的形式,具体实现方式见下文。

// 1主线程调用 @Subscribe(threadMode = ThreadMode.MAIN) public void eventBusMain(String str){ Log.i("TAG", "MAIN:"+str+" Thread="+Thread.currentThread().getId()); } // 2.发布线程为主线程,新开线程调用 // 2.发布线程为子线程,发布线程调用 @Subscribe(threadMode = ThreadMode.BACKGROUND) public void eventBusBg(String str){ Log.i("TAG", "BACKGROUND:"+str+" Thread="+Thread.currentThread().getId()); } //3,哪个线程发布,就在哪个线程调用 @Subscribe(threadMode = ThreadMode.POSTING) public void eventBusPosting(String str){ Log.i("TAG", "POSTING:"+str+" Thread="+Thread.currentThread().getId()); } // 4,每次都新开线程调用 @Subscribe(threadMode = ThreadMode.ASYNC) public void eventBusAsync(String str){ Log.i("TAG", "ASYNC:"+str+" Thread="+Thread.currentThread().getId()); }

1,调用getDefault(),里面采用单利双重锁模式创建Eventbus对象

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

2,构造方法

2.1,粘性事件,保存到ConCurrenHashMap集合,(在构造方法中实现),HashMap效率高,但线程不安全,在多线程的情况下,尽量用ConcurrentHashMap,避免多线程并发异常

EventBus(EventBusBuilder builder) { logger = builder.getLogger(); subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); //线程安全, mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; 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;}

3,注册register()方法主要做了2件事:

3.1,找到订阅者的方法.找出传进来的订阅者的所有订阅方法,然后遍历订阅者的方法.A,通过反射来获取订阅者中所有的方法,并根据方法的类型,参数和注解找到订阅方法.3.2,订阅者的注册

public void register(Object subscriber) { Class> subscriberClass = subscriber.getClass(); //找到订阅者的方法.找出传进来的订阅者的所有订阅方法,然后遍历订阅者的方法. List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { //订阅者的注册 subscribe(subscriber, subscriberMethod); } }}private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // 通过反射来获取订阅者中所有的方法 methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // ,并根据方法的类型,参数和注解找到订阅方法. methods = findState.clazz.getMethods(); findState.skipSuperClasses = true;}//通过CopyOnWriteArrayList保存Subscription, //Arraylist效率高,但线程不安全,在多线程的情况下,使用CopyOnWriteArrayList,避免多线程并发异常private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } }

3,事件发送post(),

public void post(Object event) { //PostingThreadState 保存着事件队列和线程状态信息 PostingThreadState postingState = currentPostingThreadState.get(); //获取事假队列,并将当期事件插入事件队列 List eventQueue = postingState.eventQueue; 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 { //处理队列中的所有事件, //将所有的事情交给postSingleEvent处理,并移除该事件 while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } }}

4,取消事件订阅

public synchronized void unregister(Object subscriber) { //typesBySubscriber是一个map集合, //通过subscriber找到 subscribedTypes (事件类型集合), List> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class> eventType : subscribedTypes) { unsubscribeByEventType(subscriber, eventType); } //将subscriber对应的eventType从typesBySubscriber移除 typesBySubscriber.remove(subscriber);} else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); }}

借鉴:刘望舒先生的进阶之光

Android EventBus3.1.1从使用到源码解析Android EventBus 使用详解EventBus的使用,数据传递EventBus 3.0进阶:源码及其设计模式 完全解析

查看原文 >>
相关文章