EventBus 3.0
转载链接
https://www.jianshu.com/p/acfe78296bb5
前言
EventBus是greenrobot在Android平台发布的一款以订阅—发布模式为核心的开源库。EventBus翻译过来是事件总线的意思,可以这样理解:一个个事件(event)发送到总线上,然后EventBus根据已注册的订阅者(subscribers)来匹配相应的事件,进而把事件传递给订阅者,这也是观察者模式的一个最佳实践。
那么EventBus可以用到什么地方呢?事件传递既可用于 Android 四大组件间通讯,也可以用户异步线程和主线程间通讯等等。而使用EventBus能极大简化两个组件之间的通信问题,而且效率极高,而EventBus升级到3.0版本后,开发者能够自定义订阅方法的名字,而且支持了粘性事件的分发等,因此学会使用EventBus3.0对我们的开发有极大的好处。
传统的事件传递方式包括:Handler、BroadCastReceiver、Interface 回调,相比之下 EventBus 的优点是代码简洁,使用简单,并将事件发布和订阅充分解耦。
使用
依赖
在Android Studio中添加如下依赖:
compile 'org.greenrobot:eventbus:3.0.0'
创建事件实体类
所谓的事件实体类,就是传递的事件,一个组件向另一个组件发送的信息可以储存在一个类中,该类就是一个事件,会被EventBus发送给订阅者。
public class MessageEvent {
private String message;
public MessageEvent(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
注册
即可将当前类注册,成为订阅者,即对应观察者模式的“观察者”,一旦有事件发送过来,该观察者就会接收到匹配的事件。通常,在类的初始化时便进行注册,如果是Activity则在onCreate()方法内进行注册。
EventBus.getDefault().register(this);
解除注册
当订阅者不再需要接受事件的时候,我们需要解除注册,释放内存:
EventBus.getDefault().unregister(this);
声明订阅方法
在EventBus 3.0中,声明一个订阅方法需要用到@Subscribe注解,因此在订阅者类中添加一个有着@Subscribe注解的方法即可,方法名字可自定义,而且必须是public权限,其方法参数有且只能有一个,另外类型必须为第一步定义好的事件类,如下所示:
@Subscribe
public void onEvent(AnyEventType event) {
/* Do something */
}
public class MainActivity extends Activity {
private TextView textView;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册成为订阅者
EventBus.getDefault().register(this);
textView = (TextView) findViewById(R.id.tv_text);
button = (Button) findViewById(R.id.secondActivityBtn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
//订阅方法,当接收到事件的时候,会调用该方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent messageEvent){
Log.d("cylog","receive it");
textView.setText(messageEvent.getMessage());
Toast.makeText(MainActivity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
//解除注册
EventBus.getDefault().unregister(this);
}
}
发送事件
与观察者模式对应的,当有事件发生,需要通知观察者的时候,被观察者会调用notifyObservers()方法来通知所有已经注册的观察者,在EventBus中,对观察者模式底层进行了封装,我们只需要调用以下代码就能把事件发送出去:
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_main);
Button button = (Button) findViewById(R.id.sendMessageBtn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new MessageEvent("Hello !....."));
}
});
}
}
由此可见,经过以上简单的四个步骤,就能实现事件在组件之间的传递了,这是EventBus的便捷性。
进一步认识@Subscribe注解
我们回头看看上面的订阅方法,添加了@Subscribe注解,该注解标识了当前方法为订阅方法,我们可以看到上面我们还给该注解赋值(threadMode = ThreadMode.MAIN),那么,这个代表了什么意思呢?首先,我们看看@Subscribe的类文件:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
该注解内部有三个成员,分别是threadMode、sticky、priority。threadMode代表订阅方法所运行的线程,sticky代表是否是粘性事件,priority代表优先级。给这个三个成员赋不同的值,能使得订阅方法有着不同的效果。
ThreadMode是一个枚举类型,有着以下几个类型:
public enum ThreadMode {
//发送线程(默认)
POSTING,
//主线程
MAIN,
//后台线程
BACKGROUND,
//后台线程
ASYNC
}
POSTING:表示订阅方法运行在发送事件的线程。
MAIN:表示订阅方法运行在UI线程,由于UI线程不能阻塞,因此当使用MAIN的时候,订阅方法不应该耗时过长。
BACKGROUND:表示订阅方法运行在后台线程,如果发送的事件线程不是UI线程,那么就使用该线程;如果发送事件的线程是UI线程,那么新建一个后台线程来调用订阅方法。
ASYNC:订阅方法与发送事件始终不在同一个线程,即订阅方法始终会使用新的线程来运行。
ThreadMode默认是使用POSTING的,如果需要更改设置,可以在添加注解的时候同时为threadMode赋值。
priority 优先级
设置该优先级的目的是,当一个事件有多个订阅者的时候,优先级高的会优先接收到事件。值越小优先级越低,默认为0。
sticky 粘性事件
关于粘性事件,可以参考Android的广播机制,其中有一个粘性广播,粘性广播的意思是:该广播发送后,会保存在内存中,如果后来有注册的Receiver与之匹配,那么该Receiver便会接收到该广播。那么粘性事件同理,在注册之前便把事件发生出去,等到注册之后便会收到最近发送的粘性事件(必须匹配)。注意:只会接收到最近发送的一次粘性事件,之前的会接受不到。
为了测试,我们来建立一个小demo:
我们在Activity中添加四个按钮,布局很简单不给出了,前三个按钮分别发送三个粘性事件,最后一个按钮进行注册,代码如下:
public class SecondActivity extends Activity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_main);
Button button1 = (Button) findViewById(R.id.sendStickyMessageBtn1);
Button button2 = (Button) findViewById(R.id.sendStickyMessageBtn2);
Button button3 = (Button) findViewById(R.id.sendStickyMessageBtn3);
Button button4 = (Button) findViewById(R.id.sendRegisterBtn);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.sendStickyMessageBtn1:
EventBus.getDefault().postSticky(new MessageEvent("粘性事件1"));
Log.d("cylog","发送粘性事件1...");
break;
case R.id.sendStickyMessageBtn2:
EventBus.getDefault().postSticky(new MessageEvent("粘性事件2"));
Log.d("cylog", "发送粘性事件2...");
break;
case R.id.sendStickyMessageBtn3:
EventBus.getDefault().postSticky(new MessageEvent("粘性事件3"));
Log.d("cylog", "发送粘性事件3...");
break;
case R.id.sendRegisterBtn:
Log.d("cylog", "注册成为订阅者...");
EventBus.getDefault().register(this);
break;
}
}
@Subscribe(sticky = true)
public void onEvent(MessageEvent messageEvent){
Log.d("cylog","接受到了来自EventBus的事件:"+messageEvent.getMessage());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
我们依次按下这4个按钮,按先后次序发送粘性事件1、2、3以及注册订阅者,我们可以看到下面的结果:只会接受到最后发送的粘性事件,在此之前的事件都接收不到。
建议
推荐大家在使用EventBus的时候,创建一个事件类,把你的每一个参数(或者可能发生冲突的参数),封装成一个类:
public class Event {
public static class UserListEvent {
public List<User> users ;
}
public static class ItemListEvent {
public List<Item> items;
}
}
添加processor
按照Markus Junginger的说法(EventBus创作者),在3.0中,如果你想进一步提升你的app的性能,你需要添加:
provided 'de.greenrobot:eventbus-annotation-processor:3.0.0-beta1'
其在编译的时候为注册类构建了一个索引,而不是在运行时,这样的结果是其让EventBus 3.0的性能提升了一倍,相比2.4来说,其会是它的3到6倍。