Android|EventBus使用方法

EventBus是一个Android端优化的发布/订阅事件总线,以观察者模式实现,简化了应用程序内各组件间、组件与后台线程间的通信 可以轻易切换线程、开辟线程。主要功能是替代Intent, Handler和BroadCastReceiver在Fragment, Activity, Service和线程之间传递消息。优点是开销小,代码更优雅,将发送者和接收者解耦。
Android|EventBus使用方法
文章图片

环境配置(设置依赖项)
1、使用gradle

compile 'org.greenrobot:eventbus:3.0.0'




2、使用Maven仓库



org.greenrobot eventbus 3.0.0






定义事件

public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } }


准备订阅者

【Android|EventBus使用方法】订阅者实现事件处理方法(也称为“订阅方法”),在事件发布时将被调用。 这些被定义为@Subscribe注解。


// This method will be called when a MessageEvent is posted (in the UI thread for Toast) @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show(); } // This method will be called when a SomeOtherEvent is posted @Subscribe public void handleSomethingElse(SomeOtherEvent event) { doSomethingWith(event); }


订阅者需要在总线上注册事件和取消注册事件,只有订阅者被注册了,才会接收事件。在Android中使用时,我们需要依据Activity和Fragment的生命周期来注册和解除注册事件,大部分情况下两个操作是放在onStart/onStop生命周期方法里,有时也可能是在onStart/onDestroy里。



@Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { EventBus.getDefault().unregister(this); super.onStop(); }





发布事件
我们可以从代码的任何部分发布事件,与事件类型匹配的所有当前注册的订阅者都将收到该事件。




EventBus.getDefault().post(new MessageEvent("Hello everyone!"));





使用进阶

1、ThreadMode(线程模式)
我们可以使用ThreadMode实现线程间的切换,包括后台线程、UI线程、异步线程。
ThreadMode.POSTING
//默认调用方式,在调用post方法的线程执行,避免了线程切换,性能开销最少 // Called in the same thread (default) @Subscribe(threadMode = ThreadMode.POSTING) // ThreadMode is optional here public void onMessage(MessageEvent event) { log(event.message); }


ThreadMode.MAIN


// Called in Android UI's main thread @Subscribe(threadMode = ThreadMode.MAIN) public void onMessage(MessageEvent event) { textField.setText(event.message); }


ThreadMode.BACKGROUND
// 如果调用post方法的线程不是主线程,则直接在该线程执行 // 如果是主线程,则切换到后台单例线程,多个方法公用同个后台线程,按顺序执行,避免耗时操作 // Called in the background thread @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessage(MessageEvent event){ saveToDisk(event.message); }


ThreadMode.ASYNC
//开辟新独立线程,用来执行耗时操作,例如网络访问 //EventBus内部使用了线程池,但是要尽量避免大量长时间运行的异步线程,限制并发线程数量 //可以通过EventBusBuilder修改,默认使用Executors.newCachedThreadPool() // Called in a separate thread @Subscribe(threadMode = ThreadMode.ASYNC) public void onMessage(MessageEvent event){ backend.send(event.message); }


2、配置EventBusBuilder
EventBus提供了很多配置,一般的情况下我们可以不用配置.但是,如果你有一些其他要求,比如控制日志在开发的时候输出,发布的时候不输出,在开发的时候错误崩溃,而发布的时候不崩溃...等情况。EventBus提供了一个默认的实现,但不是单例。
EventBus eventBus = new EventBus(); //下面这一条的效果是完全一样的 EventBus eventBus = EventBus.builder().build(); //修改默认实现的配置,记住,必须在第一次EventBus.getDefault()之前配置,且只能设置一次。建议在application.onCreate()调用 EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus();


3、StickyEvent
StickyEvent在内存中保存最新的消息,取消原有消息,执行最新消息,只有在注册后才会执行,如果没有注册,消息会一直保留来内存中。
//在注册之前发送消息 EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));

//限制,新界面启动了 @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } //在onStart调用register后,执行消息 @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEvent(MessageEvent event) { // UI updates must run on MainThread textField.setText(event.message); }@Override public void onStop() { EventBus.getDefault().unregister(this); super.onStop(); }


你也可以手动管理StickyEvent
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class); // Better check that an event was actually posted before if(stickyEvent != null) { // "Consume" the sticky event EventBus.getDefault().removeStickyEvent(stickyEvent); //or EventBus.getDefault().removeAllStickyEvents(); // Now do something with it }


因为post方法没有过滤StickyEvent,而postSticky是调用post方法的,所以,无论post还是postSticky,StickyEvent是true或false,都会执行。
4、priority事件优先级
//priority越大,级别越高 @Subscribe(priority = 1); public void onEvent(MessageEvent event) { … }


int size = subscriptions.size(); for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } }


5、中止事件传递
// 中止事件传递,后续事件不在调用,注意,只能在传递事件的时候调用 @Subscribe public void onEvent(MessageEvent event){ … EventBus.getDefault().cancelEventDelivery(event) ; }


6、index索引加速
EventBus使用了annotation,默认在编译时生成代码,生成索引,添加index后会在编译时运行,自动生成相应代码。
buildscript { dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } apply plugin: 'com.neenbedankt.android-apt' dependencies { compile 'org.greenrobot:eventbus:3.0.0' apt 'org.greenrobot:eventbus-annotation-processor:3.0.1' } apt { arguments { eventBusIndex "com.example.myapp.MyEventBusIndex" } }


EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();


EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus(); // Now the default instance uses the given index. Use it like this: EventBus eventBus = EventBus.getDefault();


7、NoSubscriberEvent

如果没找到订阅者事件,可以通过EventBusBuilder设置是否默认发送NoSubscriberEvent,默认是打开的。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { .... if (!subscriptionFound) { if (logNoSubscriberMessages) { Log.d(TAG, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }


8、混淆

-keepattributes *Annotation* -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe ; } -keep enum org.greenrobot.eventbus.ThreadMode { *; }# Only required if you use AsyncExecutor -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { (java.lang.Throwable); }




9、建议
将数据封装到一个事件类。所有事件放到一个包下。如果事件太多,同个模块的事件可以考虑使用静态内部类,或者再分包。
public class Event{ public static class AListEvent { public List aList ; } public static class BListEvent { public List bList; } }



注意:注册和取消注册前要做是否已注册判断,否则会有Subscriber class already registered to event class异常
@Override protected void onStart() { super.onStart(); if (!EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().register(this); } }@Override public void onStop() { if (EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().unregister(this); } super.onStop(); }





    推荐阅读