一、概念
EventBus是一款在 Android 开发中使用的发布-订阅事件总线框架,基于观察者模式,将事件的接收者和发送者解耦,简化了组件之间的通信,使用简单、效率高、体积小。
一句话:用于Android组件间通信的。
二、原理
三、简单使用
- 在app module的builde.gradle文件中导入依赖库:
implementation 'org.greenrobot:eventbus:3.3.1'
- 配置混淆
-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);
}
1、订阅者EventBusService后台注册,前台EventBusActivity 发送的数据。注册以后一定要记得解注册,否则会内存泄漏。onMsgEventReceived
是接收消息的方法,该方法定义需要注意:
- 该方法有且仅有一个参数;
- 必须用
public
修饰,不能使用static
或者abstract
; - 需要添加
@Subscribe()
注解;
public class EventBusService extends Service {
private static final String TAG = "Test_EventBusService";
@Override
public void onCreate() {
super.onCreate();
//注册数据监听
EventBus.getDefault().register(this);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Subscribe
public void onMsgEventReceived(String msg) {
Log.i(TAG, "String msg: " + msg);
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 1)
public void onMsgEventReceived(MsgEvent event) {
Log.i(TAG, "MsgEvent msg: " + event.getMsg());
}
@Override
public void onDestroy() {
super.onDestroy();
//解注册数据监听
EventBus.getDefault().unregister(this);
}
}
2、前台Activity在按钮点击的时候发送信息到后台Service。
public class EventBusActivity extends AppCompatActivity {
private static final String TAG = "Test_EventBusActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
Button msg1Btn = findViewById(R.id.btn1);
Button msg2Btn = findViewById(R.id.btn2);
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
EventBus.getDefault().post("msg1 - coming!!!");
}
});
msg2Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
MsgEvent event = new MsgEvent("msg2 - coming!!!");
EventBus.getDefault().post(event);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
3、MsgEvent数据类型。
public class MsgEvent {
private String msg;
public MsgEvent(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "MsgEvent{" +
"msg='" + msg + '\'' +
'}';
}
}
4、运行结果
四、Subscribe注解
Subscribe是EventBus自定义的注解,共有三个参数(可选):ThreadMode
、boolean sticky
、int priority
。
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 1)
public void onMsgEventReceived(MsgEvent event) {
Toast.makeText(this, event.getMsg(), Toast.LENGTH_LONG).show();
}
1、ThreadMode取值:
- ThreadMode.POSTING:默认的线程模式,在哪个线程发送事件就在对应线程处理事件。避免了线程切换,效率高。
代码测试:
#EventBusActivity
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
new Thread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
}
}).start();
}
});
#EventBusService
@Subscribe
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
}
把post
的动作放到子线程中,结果如下,在哪个线程发送,就会在哪个线程执行:
-
ThreadMode.MAIN:如在主线程(UI线程)发送事件,则直接在主线程处理事件;如果在子线程发送事件,则先将事件入队列,然后通过
Handler
切换到主线程,依次处理事件。
该模式下,在主线程(UI线程)发送事件,则直接在主线程处理事件,如果处理方法中有耗时操作就会堵塞进程。
代码测试1:
#EventBusActivity
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
new Thread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
}
}).start();
}
});
#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
}
发送post
代码放到子线程中,处理事件代码加上ThreadMode.MAIN
注解参数,结果如下,可以用在子线程处理耗时操作,然后返回值需要切回到主线程刷新UI的场景:
代码测试2:
#EventBusActivity
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1-1 - coming!!!");
}
});
#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
发送post
放在主线程并连续发送两次,接收事件的函数加上耗时操作,运行结果如下,两次post
打印就相隔2s,第二次post
需要等第一次事件接收处理完以后才能发出,所以主线程会阻塞:
同样修改下发出post
的代码放到子线程后没有这个问题,结果如下:
-
ThreadMode.MAIN_ORDERED:无论在那个线程发送事件,都先将事件入队列,然后通过
Handler
切换到主线程,依次处理事件。
代码测试:
#EventBusActivity
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1-1 - coming!!!");
}
});
#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
代码和ThreadMode.MAIN
测试2一样,只是将threadMode
改为了MAIN_ORDERED
,运行结果如下,两次post
可以连续发出:
-
ThreadMode.BACKGROUND:如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件;如果在子线程发送事件,则直接在发送事件的子线程处理事件。
代码测试1:
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
}
});
#EventBusService
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
}
运行结果如下,主线程发送事件,线程池依次处理事件:
代码测试2:
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
new Thread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
}
}).start();
}
});
#EventBusService
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
}
运行结果,子线程发送事件,则直接在发送事件的子线程处理事件:
-
ThreadMode.ASYNC:无论在那个线程发送事件,都将事件入队列,然后通过线程池处理。
代码测试1:
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
}
});
#EventBusService
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
}
运行结果,主线程发送,线程池处理:
代码测试2:
msg1Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送数据给监听者
new Thread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "post thread: " + Thread.currentThread().getName());
EventBus.getDefault().post("msg1 - coming!!!");
}
}).start();
}
});
#EventBusService
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMsgEventReceived(String msg) {
Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
Log.i(TAG, "String msg: " + msg);
}
运行结果,子线程发送,线程池处理:
2、sticky:
sticky
是否为粘性监听,boolean类型,默认值为false。正常我们都是先订阅,才能接收到发出的事件,sticky的作用就是订阅者可以先不进行注册,事件先发出,再注册订阅者,同样可以接收到事件,并进行处理。
3、priority:
priority
是优先级,int类型,默认值为0。值越大,优先级越高,越优先接收到事件。值得注意的是,只有在post
事件和事件接收处理,处于同一个线程环境的时候,才有意义。
参考文章
EventBus详解 (详解 + 原理)