使用EventBus进行组件间通讯
2015-12-24 11:30
393 查看
你是否已经厌倦了在两个Fragment之间传递数据,是否已经厌倦了Service与Activity/Fragment之间的通讯,是否已经厌倦了startActivityForResult中的requestCode, resultCode. 快来试试EventBus吧~
EventBus看名字可以理解成是一个传递事件的公交车,实际上,EventBus也的确是做这个事情。使用的时候,在合适的地方发布一个事件,注册了该事件接收的对象就可以收到通知,进行相应的操作。
EventBus能够很方便的解决上面遇到的麻烦,可以让代码看起来更简洁,写起来更方便,自然也就更少机会的犯错。第一眼看到EventBus的那种解放感已经可以和ButterKnife比肩了。
先从最简单的UploadProgressEvent看,EventBus并不要求Event对象实现什么接口或者继承什么父类,Event对象可以是任意的POJO. 我们这里用到的UploadProgressEvent只需要有一个progress字段就好了,来标识当前上传的进度,取值范围0-100.
public class UploadProgressEvent {
private int progress;
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
}
再看一下一个模拟上传的FileUploadService,继承自IntentService,可以默认在新的线程运行,并且可以自动结束。
public class FileUploadService extends IntentService {
private UploadProgressEvent uploadProgressEvent;
public FileUploadService(String name) {
super(name);
uploadProgressEvent = new UploadProgressEvent();
}
@Override
protected void onHandleIntent(Intent intent) {
…
IO.putFile(this, UP_TOKEN, key, uri, extra, new JSONObjectRet() {
@Override
public void onProcess(long current, long total) {
int progress = (int) (current * 100 / total);
uploadProgressEvent.setProgress(progress);
EventBus.getDefault().post(uploadProgressEvent);
}
});
}
}
上面可以看出,每次得到onProgress时候,都会设置一下最新的progress数据,发布一个uploadProgressEvent对象到bus. bus则会很勤快的载着我们的Event到它想去的地方。当然是对应的现实UI的UploadFragment.
public class UploadFragment extends BaseFragment{
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
public void onEvent(UploadProgressEvent event) {
int progress = event.getProgress();
// TODO 更新UI
}
}
在Fragment里面的onStart方法和onStop方法分别进行了EventBus的注册与撤销注册。值得注意的是onEvent方法,该方法接受一个UploadProgressEvent参数。EventBus正是通过这个方法来处理UploadProgressEvent事件的。
看了上面的实例是不是很方便?简单来说,就是A组件与B组件,B组件注册了EventBus之后,A组件发生了事件X,则会通知响应的注册了EventBus的B组件的onEvent(X)的方法处理,so easy~
public void onEventMainThread(MessageEvent event) {
textField.setText(event.message);
}
直接使用onEventMainThread方法来处理响应的Event,声明成onEventMainThread的方法会在主机线程运行,这样就可以肆无忌惮的修改UI了。
与onEventMainThread对应的还有onEventBackgroundThread,顾名思义,该方法会在一个Background线程执行,但是这个Background线程是怎么定义的呢?其实Background是指非UI线程,也就是说post(Event)如果是UI线程,那么,onEventBackgroundThread会在另外一个非UI线程执行;如果post(Event)是在一个非UI线程,那么onEventBackgroundThread则和onEvent方法一样,直接在当前线程执行。
除onEvent和onEventBackgroundThread之外,还有一个onEventAsync方法,该方法更简单,不管post(Event)是否是UI线程,onEventAsync都会在一个新的线程执行。
那么怎么用EventBus来模拟这样的情况呢?这就需要另外一个强大的机制,Sticky Event.
和普通的Event不同,当发布一个Sticky Event,需要使用postSticky方法:
EventBus.getDefault().postSticky(new VoteEvent(obj));
上面的代码发布了一个点赞的Sticky Event.
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().registerSticky(this);
}
public void onEventMainThread(VoteEvent event) {
// TODO update adapter
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
上面的代码则是在对应的列表页面,onStart方法调用了EventBus的registerSticky方法,该方法在每次执行的时候,都回去查询一次Sticky Event,并调用响应的方法处理。本例中,当列表页面第一次显示的时候,是没有Sticky Event的,所以registerSticky不会触发任何事件;而当列表页面是由详情页退出后显示出来的话,registerSticky会触发在详情页postSticky的VoteEvent,而触发onEventMainThread(VoteEvent)方法,以达到onActivityResult方法的效果。
除了registerSticky方法来触发Sticky Event之外,我们还可以通过getStickyEvent方法来获取响应的Sticky Event来进行处理。比如:
@Override
public void onResume() {
super.onResume();
VoteEvent voteEvent = EventBus.getDefault().getStickyEvent(VoteEvent.class);
// TODO update adapter if vote event is not null.
}
我们可以在每次的onResume方法里面检查EventBus里面是否有VoteEvent的Sticky Event,从而进行处理。
总之,EventBus极大的减轻了我们各种组件之间的通讯复杂度,也大大减少了使用Activity Result的麻烦。真实值得极力推荐。
EventBus看名字可以理解成是一个传递事件的公交车,实际上,EventBus也的确是做这个事情。使用的时候,在合适的地方发布一个事件,注册了该事件接收的对象就可以收到通知,进行相应的操作。
EventBus能够很方便的解决上面遇到的麻烦,可以让代码看起来更简洁,写起来更方便,自然也就更少机会的犯错。第一眼看到EventBus的那种解放感已经可以和ButterKnife比肩了。
基本使用,组件之间通讯
这里假设一个上传文件的场景,有一个上传文件的Service: FileUploadService;以及一个显示进度的UI: UploadFragment;以及一个用来传递上传进度的Event: UploadProgressEvent.先从最简单的UploadProgressEvent看,EventBus并不要求Event对象实现什么接口或者继承什么父类,Event对象可以是任意的POJO. 我们这里用到的UploadProgressEvent只需要有一个progress字段就好了,来标识当前上传的进度,取值范围0-100.
public class UploadProgressEvent {
private int progress;
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
}
0 1 2 3 4 5 6 7 8 9 10 11 12 | public class UploadProgressEvent { private int progress; public int getProgress() { return progress; } public void setProgress(int progress) { this.progress = progress; } } |
public class FileUploadService extends IntentService {
private UploadProgressEvent uploadProgressEvent;
public FileUploadService(String name) {
super(name);
uploadProgressEvent = new UploadProgressEvent();
}
@Override
protected void onHandleIntent(Intent intent) {
…
IO.putFile(this, UP_TOKEN, key, uri, extra, new JSONObjectRet() {
@Override
public void onProcess(long current, long total) {
int progress = (int) (current * 100 / total);
uploadProgressEvent.setProgress(progress);
EventBus.getDefault().post(uploadProgressEvent);
}
});
}
}
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class FileUploadService extends IntentService { private UploadProgressEvent uploadProgressEvent; public FileUploadService(String name) { super(name); uploadProgressEvent = new UploadProgressEvent(); } @Override protected void onHandleIntent(Intent intent) { … IO.putFile(this, UP_TOKEN, key, uri, extra, new JSONObjectRet() { @Override public void onProcess(long current, long total) { int progress = (int) (current * 100 / total); uploadProgressEvent.setProgress(progress); EventBus.getDefault().post(uploadProgressEvent); } }); } } |
public class UploadFragment extends BaseFragment{
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
public void onEvent(UploadProgressEvent event) {
int progress = event.getProgress();
// TODO 更新UI
}
}
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class UploadFragment extends BaseFragment{ @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } public void onEvent(UploadProgressEvent event) { int progress = event.getProgress(); // TODO 更新UI } } |
看了上面的实例是不是很方便?简单来说,就是A组件与B组件,B组件注册了EventBus之后,A组件发生了事件X,则会通知响应的注册了EventBus的B组件的onEvent(X)的方法处理,so easy~
指定处理线程
默认情况下,onEvent方法会在post(Event)的方法的线程中执行,但是可能会post(Event)是一个非UI线程,而onEvent方法需要更新UI,需要在主线程运行。这时候可以写一个post(Runnable)啥啥啥。但是EventBus提供了一个更简洁的处理方式。public void onEventMainThread(MessageEvent event) {
textField.setText(event.message);
}
0 1 2 3 4 | public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } |
与onEventMainThread对应的还有onEventBackgroundThread,顾名思义,该方法会在一个Background线程执行,但是这个Background线程是怎么定义的呢?其实Background是指非UI线程,也就是说post(Event)如果是UI线程,那么,onEventBackgroundThread会在另外一个非UI线程执行;如果post(Event)是在一个非UI线程,那么onEventBackgroundThread则和onEvent方法一样,直接在当前线程执行。
除onEvent和onEventBackgroundThread之外,还有一个onEventAsync方法,该方法更简单,不管post(Event)是否是UI线程,onEventAsync都会在一个新的线程执行。
使用Sticky Events
某些时候,我们并不希望发布出来的Event立即被消费掉,而是等到时机成熟。比如说,在一个详情页点赞之后,产生一个VoteEvent,VoteEvent并不立即被消费,而是等用户退出详情页回到商品列表之后,接收到该事件,然后刷新Adapter等。其实这就是之前我们用startActivityForResult和onActivityResult做的事情。那么怎么用EventBus来模拟这样的情况呢?这就需要另外一个强大的机制,Sticky Event.
和普通的Event不同,当发布一个Sticky Event,需要使用postSticky方法:
EventBus.getDefault().postSticky(new VoteEvent(obj));
0 1 2 | EventBus.getDefault().postSticky(new VoteEvent(obj)); |
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().registerSticky(this);
}
public void onEventMainThread(VoteEvent event) {
// TODO update adapter
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Override public void onStart() { super.onStart(); EventBus.getDefault().registerSticky(this); } public void onEventMainThread(VoteEvent event) { // TODO update adapter } @Override public void onStop() { EventBus.getDefault().unregister(this); super.onStop(); } |
除了registerSticky方法来触发Sticky Event之外,我们还可以通过getStickyEvent方法来获取响应的Sticky Event来进行处理。比如:
@Override
public void onResume() {
super.onResume();
VoteEvent voteEvent = EventBus.getDefault().getStickyEvent(VoteEvent.class);
// TODO update adapter if vote event is not null.
}
0 1 2 3 4 5 6 7 | @Override public void onResume() { super.onResume(); VoteEvent voteEvent = EventBus.getDefault().getStickyEvent(VoteEvent.class); // TODO update adapter if vote event is not null. } |
总之,EventBus极大的减轻了我们各种组件之间的通讯复杂度,也大大减少了使用Activity Result的麻烦。真实值得极力推荐。
相关文章推荐
- Action Link开发模式
- mysql 获取当前日期及格式化(一)
- BASE64、MD5、SHA、HMAC几种加密算法
- jqGrid 各种参数 详解
- Jsoup 网页抓取数据之获取汽车时刻表 实例解析
- PHP序列化与反序列化解读
- 有趣的checkbox动画切换状态(支付宝转账成功显示)--第三方开源--AnimCheckBox
- PHP读取Excel里的文件
- 工厂模式 jdbc 面向接口dao 开发 单例
- virtualbox pxe启动
- json 转换为 map、对象
- Android之菜单选项Menu(一)
- 思科交换机提供的三种交换模式
- LeetCode 035 Search Insert Position
- 编译安装及配置PHP7
- 数组名取地址所算数运算应注意的"trap"
- JNDI全面总结(zz)
- 代码整洁之道【书】--03
- python包安装——Swig
- log4j框架logger的继承关系以及使用场景