EventBus3.0基本使用
一.概述
EventBus是一个用于Android和Java的开源库,使用发布者/订阅者模式实现松散耦合。EventBus使*通信仅用几行代码就能解耦类——简化代码、消除依赖和加速应用程序开发。
二.使用
1.依赖
compile 'org.greenrobot:eventbus:3.0.0'
2.代码中基本使用
(1)首先先定义一个事件,用于事件的发布和消息传递
public class MessageEvent {
String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
(2)订阅者进行注册和反注册
订阅者进行注册
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_home);
super.onCreate(savedInstanceState);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
取消订阅
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
(3)订阅者订阅方法例子: threadMode和priority见方法上的注释
/**
* ThreadMode.MAIN 事件发送者不论在哪个线程,订阅者都在主线程接收用于刷新ui
* priority 越大越先收到
* @param event
*/
@Subscribe(threadMode = ThreadMode.MAIN, priority = 0)
public void onMessageEvent(MessageEvent event) {
LogUtil.d(TAG, "onMessageEvent MAIN priority0", event.getMessage(), " thread: ", Thread.currentThread().getName());
}
/**
* ThreadMode.MAIN 事件发送者不论在哪个线程,订阅者都在主线程接收用于刷新ui
* priority 越大越先收到
* @param event
*/
@Subscribe(threadMode = ThreadMode.MAIN, priority = 1)
public void onMessageEvent2(MessageEvent event) {
LogUtil.d(TAG, "onMessageEvent2 MAIN priority1", event.getMessage(), " thread: ", Thread.currentThread().getName());
}
/**
* ThreadMode.POSTING(默认) 订阅者和事件发送者在同一个线程
* priority 越大越先收到
* @param event
*/
@Subscribe(threadMode = ThreadMode.POSTING, priority = 1)
public void onMessageEvent3(MessageEvent event) {
LogUtil.d(TAG, "onMessageEvent3 POSTING", event.getMessage(), " thread: ", Thread.currentThread().getName());
}
/**
* ThreadMode.BACKGROUND
* 事件发送者在主线程的话,订阅者会在创建的子线程中
* 事件发送者不在主线程的话,订阅者和事件发送者在同一个线程
* priority 越大越先收到
* @param event
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 1)
public void onMessageEvent4(MessageEvent event) {
LogUtil.d(TAG, "onMessageEvent4 BACKGROUND", event.getMessage(), " thread: ", Thread.currentThread().getName());
}
/**
* ThreadMode.ASYNC
* 不论事件发送者在哪一个线程,订阅者都会在重新创建的子线程中
* priority 越大越先收到
* @param event
*/
@Subscribe(threadMode = ThreadMode.ASYNC, priority = 1)
public void onMessageEvent5(MessageEvent event) {
LogUtil.d(TAG, "onMessageEvent5 ASYNC", event.getMessage(), " thread: ", Thread.currentThread().getName());
}
总结一下: EventBus的四种ThreadMode(线程模型)
EventBus3.0有以下四种ThreadMode:
- POSTING(默认):如果使用事件处理函数指定了线程模型为POSTING,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
- MAIN: 事件的处理会在UI线程中执行。事件处理时间不能太长,长了会ANR的。
- BACKGROUND:如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
- ASYNC:无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行,同样,此事件处理函数中禁止进行UI更新操作。 (4)事件发布者用法如下: 另起一个activity进行事件发布:
new Thread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new MessageEvent("work thread message"));
}
}).start();
EventBus.getDefault().post(new MessageEvent("main thread test"));
我在子线程和主线程中各发布了一个消息,事件订阅者接收到的log如下:
05-29 13:49:48.050 22933 22933 D HomeActivity: onMessageEvent3 POSTING main thread test thread: main
05-29 13:49:48.050 22933 22933 D HomeActivity: onMessageEvent2 MAIN priority1 main thread test thread: main
05-29 13:49:48.050 22933 22933 D HomeActivity: onMessageEvent MAIN priority0 main thread test thread: main
05-29 13:49:48.050 22933 22982 D HomeActivity: onMessageEvent5 ASYNC main thread test thread: pool-1-thread-1
05-29 13:49:48.051 22933 22981 D HomeActivity: onMessageEvent4 BACKGROUND work thread message thread: Thread-209
05-29 13:49:48.051 22933 22984 D HomeActivity: onMessageEvent5 ASYNC work thread message thread: pool-1-thread-3
05-29 13:49:48.051 22933 22981 D HomeActivity: onMessageEvent3 POSTING work thread message thread: Thread-209
05-29 13:49:48.052 22933 22983 D HomeActivity: onMessageEvent4 BACKGROUND main thread test thread: pool-1-thread-2
05-29 13:49:48.060 22933 22933 D HomeActivity: onMessageEvent2 MAIN priority1 work thread message thread: main
05-29 13:49:48.060 22933 22933 D HomeActivity: onMessageEvent MAIN priority0 work thread message thread: main
3.拦截事件的方法源码如下:
public void cancelEventDelivery(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
if (!postingState.isPosting) {
throw new EventBusException(
"This method may only be called from inside event handling methods on the posting thread");
} else if (event == null) {
throw new EventBusException("Event may not be null");
} else if (postingState.event != event) {
throw new EventBusException("Only the currently handled event may be aborted");
} else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) {
throw new EventBusException(" event handlers may only abort the incoming event");
}
postingState.canceled = true;
}
可以看到拦截事件只能在ThreadMode是POSTING的方法上进行拦截
4.粘性事件
除了上面讲的普通事件外,EventBus还支持发送黏性事件,就是在发送事件之后再订阅该事件也能收到该事件,跟黏性广播类似。
事件发布者发布的事件会保存在内存中,当有订阅者注册已发布的粘性事件时,会直接收到已发布的粘性事件。 在上面例子添加粘性事件代码如下:
发送者先发送粘性事件
EventBus.getDefault().postSticky(new MessageEvent("粘性事件"));
发送者发送粘性事件后,订阅者再去订阅,可以写在onclick()中去订阅:
mStickyBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
});
订阅粘性事件方法如下:
/**
* 订阅粘性事件
* @param event
*/
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
public void onMessageEventSticky(MessageEvent event) {
LogUtil.d(TAG, "onMessageEventSticky", event.getMessage(), " thread: ", Thread.currentThread().getName());
}
运行顺序:发布者先发布粘性事件,然后点击按钮订阅者进行注册,然后订阅者收到粘性事件,log如下:
05-29 14:39:39.756 28301 28301 D SystemGarbageActivity: 发布粘性事件 message: 粘性事件
05-29 14:39:44.039 28301 28301 D HomeActivity: 订阅者注册
05-29 14:39:44.042 28301 28301 D HomeActivity: onMessageEventSticky 粘性事件 thread: main
三.ProGuard 混淆规则
-keepattributes *Annotation*
-keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}