1、背景介绍
如果你学习过设计模式,那么当想通知其他组件某些事情发生时你一定会使用观察者模式。好了,既然能想到这个设计模式,那么就来看一个屌爆天的Android开源框架EventBus。主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、线程之间传递消息。他的最牛逼优点是开销小,代码简洁,解耦代码。
2、EventBus的概念和理解
EventBus**是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间、组件与后台线程间的通信。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过**EventBus**实现。
作为一个消息总线,有三个主要的元素:
- Event:事件
- Subscriber:事件订阅者,接收特定的事件
- Publisher:事件发布者,用于通知Subscriber有事件发生
总之,就是通过订阅和发布,订阅发布者的信息。并完成通信的操作。
onEvent:使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。
onEventMainThread:无论事件在哪个线程发布出来的,始终在UI线程中执行订阅事件的操作。
onEventBackground:无论事件在哪个线程发布出来的,始终在工作线程中执行订阅事件的操作。
onEventAsync:使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行
(3)发布者,格式是: EventBus.getDefault().post(object);
3、如何使用EventBus
官方给出的使用方式是:
(1)Define events://定义事件 public class MessageEvent { /* Additional fields if needed */ }
(2)Prepare subscribers//注册订阅者 Register your subscriber (in your onCreate or in a constructor): eventBus.register(this);
(3)Declare your subscribing method://订阅事件的动作 @Subscribe public void onEvent(AnyEventType event) {/* Do something */};
(4)Post events://发布者发送事件 eventBus.post(event);
(1) 注册EventBus
(2)注销EventBus
(3) 发布EventBus
(4)订阅EventBus
4、Demo项目的实战
接下来做一个借着注册的界面实现以下操作,实际并不是用于注册(请注意了,注意思想就好)!
(1) 首先记得加上jar包 在Android studio 的 app下的 build 加上compile 'org.greenrobot:eventbus:3.0.0'
代码块:
public class MainActivity extends AppCompatActivity {
private TextView tv1,tv_status;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);//在当前界面注册一个订阅者 // 1**
tv1=(TextView)findViewById(R.id.tv);
tv_status=(TextView)findViewById(R.id.tv_status);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(),
LoginActivity.class);
startActivity(intent); } }); }
@Subscribe //订阅事件FirstEvent
public void onEventMainThread(LoginSuccessdEvent event){ // 2**
String msg=event.getMsg();
tv_status.setText("已登录,当前账号"+msg);//获取事件中传递的参数
Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); }
@Override protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);//取消注册 }} //3**
以上方法中 1** 的 当你需要在哪个界面订阅的时候都需要在里面注册 (不过还有一种情况是先拿到事件,然后在订阅 ,这就是所谓的粘性事件,,,感兴趣的可以自己查查)
2** 当需要订阅的时候 都需要选择 Subscriber 约定的onEvent为开头的四种函数其中的一种,然后参数就是上面说的event 他可以是任何对象
3** 既然注册了,就需要注销 ,防止内存溢出。这个就不用多说了
(2) 发布事件
其实就是很简单的一局代码:EventBus.getDefault().post(new 这里就是你的自己定义的事件);
(3) 定义事件
随便举例定义的事件,实际按各位需要的定义事件:
public class LoginSuccessdEvent {
private String msg;
public LoginSuccessdEvent(String msg) {
//事件传递参数
this.msg = msg; }
public String getMsg() {
//取出事件参数
return msg; }
public void setMsg(String msg) {
this.msg = msg;
}}
EventBus的基本使用官方参考:https://github.com/greenrobot/EventBus
另外在推荐 一篇和好的文章 :http://www.cnblogs.com/angeldevil/p/3715934.html
4、EventBus的使用方向
对比Java监听器接口(Listener Interfaces)
在Java中,特别是Android,一个常用的模式就是使用”监听器(Listeners)”接口。在此模式中,一个实现了监听器接口的类必须将自身注册到它想要监听的类中去。这就意味着监听与被监听之间属于强关联关系。这种关系就使得单元测试很难进行开展。Jake Wharton在他的《使用Otto解耦Android应用间通信》这篇文章中很好地阐述了这个问题,在此我就不进行展开了。
对比本地广播管理器(LocalBroadcastManager)
另一项技术就是在组件间通过本地广播管理器(LocalBroadcastManager)进行消息的发送与监听。虽然这对于解耦有很好的帮助,但它的API不如EventBus那样简洁。此外,如果你不注意保持Intent extras类型的一致,它还可能引发潜在的运行时/类型检测错误。
考虑下面的应用场景:
组件A执行一个批量异步数据库更新操作。当成功完成时,它发送一条通知告诉更新了多少条记录。发生错误时,发送一条通知包含了错误信息。
组件B则需要知道到更新是否完成和更新了多少条记录,以及是否有错误发生和错误信息。
使用LocalBroadcastManager,最简单的代码大概如下面所示。
组件A:
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 | // when update completes successfully Intent intent = new Intent(); intent.setAction(FILTER_ACTION_UPDATE_SUCCESS); intent.putExtra(EXTRA_COUNT, count); LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
...
// when there is an error Intent intent = new Intent(); intent.setAction(FILTER_ACTION_UPDATE_ERROR); intent.putExtra(EXTRA_ERROR_MSG, error.getMessage()); LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); |
组件B:
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | IntentFilter updateSuccessFilter = new IntentFilter(FILTER_ACTION_UPDATE_SUCCESS); BroadcastReceiver updateSuccessReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int updateCount = intent.getIntExtra(EXTRA_COUNT, -1); // TODO - do something with the count } };
IntentFilter updateErrorFilter = new IntentFilter(FILTER_ACTION_UPDATE_ERROR); BroadcastReceiver updateErrorReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String errorMsg = intent.getStringExtra(EXTRA_ERROR_MSG); // TODO - display error message or similar } };
...
getContext().registerReceiver(updateSuccessReceiver, updateSuccessFilter); getContext().registerReceiver(updateErrorReceiver, updateErrorFilter);
...
getContext().unregisterReceiver(updateSuccessReceiver); getContext().unregisterReceiver(updateErrorReceiver); |
使用EventBus,同样功能实现可以表示如下。(注:此例中我使用的是我的EventBus实现,参见Green Robot的EventBus。)
Event类:
Java
1 2 3 4 5 6 7 | public class UpdateCompleteEvent { public final int count;
UpdateCompleteEvent(int count){ this.count = count; } } |
Java
1 2 3 4 5 6 7 | public class UpdateErrorEvent { public final String message;
UpdateCompleteEvent(String message){ this.message = message; } } |
组件A:
Java
1 2 3 4 5 6 7 8 9 10 | EventBus bus = EventBus.getDefault(); // Or better yet, inject it
...
// when update completes successfully bus.post(new UpdateCompleteEvent(count)); ...
// when there is an error bus.post(new UpdateErrorEvent(error.getMessage())); |
组件B:
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | EventBus bus = EventBus.getDefault(); // Or better yet, inject it
...
public void onEvent(UpdateCompleteEvent event){ // TODO - do something with event.count }
public void onEvent(UpdateErrorEvent event){ // TODO - do something with event.message }
...
bus.register(this);
...
bus.unregister(this); |