本帖最后由 武汉-就业部 于 2017-9-1 13:48 编辑
一:EventBus简介
讲解怎么EventBus怎么用之前,先说说这玩意是干什么的。
EventBus在我的理解中就是帮我们实现好的接口回调,同时可以指定回调代码在哪个线程执行,之所以用户很多,就是因为他使用起来非常的简单,两行代码就可以实现回调的需求。
二:EventBus的使用
1、入门篇
想要使用EventBus,在AndroidStudio中添加如下依赖(或者下载jar包):
compile 'org.greenrobot:eventbus:3.0.0'
EventBus的使用非常简单,只需要两行代码就可以了,一个是注册该事件,一个是发出事件,这样一来注册事件的类就可以收到消息,在注册事件所在类中 写的方法就会被回调。
我们来实现一个简单的需求。在一个Activity中显示两个Fragment,两个Fragment中各有一个Button,需求是点击Fragment1中的Button,改变Fragment2中Button中的text。效果图如下:
这个需求对我我们这种高贵的程序员来讲太简单了吧,对于没有接触过EventBus的童鞋来说,首先想到的是什么呢?接口回调、或者使用getActivity来实现。这样写确实可以实现,但是太过麻烦,如果不是两个Fragment而是两个不相干的类,那写起来就会很麻烦了。下面就开始说说用EventBus3.0来实现这个需求的逻辑代码。
首先我们分析一下这个需求:
1:Fragment1是一个事件源点击之后发出事件
2:Fragment2是一个订阅者,当事件源发出事件之后改变Button中的text
接下来我们根据需求开始处理这两个类,先来处理订阅者Fragment2,让订阅者订阅这个事件:
//通过这个方法,订阅事件,让Fragment2有接收到Fragment1发出事件的资格
EventBus.getDefault().register(this);
订阅完事件之后就需要写接收到事件之后相应的处理了,这里我们写一个方法,让收到事件之后该方法被调用。
/**
* @Subscribe 这个注解就相当于指定接收到事件之后该方法被调用
* @param text 这个参数就是事件源发出事件传递过来的值
*/
@Subscribe
public void changeText(String text){
mButton.setText(text);
}
到这里,Fragment2里面的逻辑已经写的差不多了,但是不要忘记如下这个代码:
public void onDestroy() {
super.onDestroy();
//当Fragment被销毁的时候注销掉这个订阅事件,减少不必要的内存泄漏
EventBus.getDefault().unregister(this);
}
接下来开始处理事件源Fragment1,这里只需要当Button被点击的时候发出一个事件:
//通过post方法来发出事件,同时传递参数
EventBus.getDefault().post("变身成功");
到这里我们的需求就已经实现了,是不是很简单。
我们来总结一下EventBus的基本使用:
EventBus.getDefault().register(this);//该方法用于让需要获取到事件的类订阅事件,有接收到事件的资格(写在需要接收到事件的类中)
EventBus.getDefault().unregister(this);//这个方法和上面的方法相对应,用于注销这个订阅(写在需要接收到事件的类中)
EventBus.getDefault().post(object);//这个方法用于发出事件,同时传递参数(写在事件源所在的类中)
/**
* 发方法用于真正处理事件
* 当接收到发出的事件之后这个方法会被调用,并接收到事件传递过来的参数(写在需要接收到事件的类中)
*/
@Subscribe
public void xxxx(Object object){
}
2、基础篇
通过上述的讲解,大家应该能了解EventBus的基本使用了,细心的朋友应该已经发现接收到事件的回调方法里面的参数是Object对象,这意味着什么大家应该都很清楚。说明EventBus异常的强大,可以传递任何类型的数据。上面的Demo中我们传递的是String类型的数据,但是在开发中需要传递到东西可不仅仅这么简单,通常需要传递的会是一个Bean。而且事件源并不一定的在主线程,很有可能是子线程中获取到数据之后来发出事件,那么问题来了,事件是在子线程中发出的,那我接收到事件之后的方法回调是在哪个线程呢?我们通常希望的是在主线程,这样就可以直接做数据的显示。
EventBus里面对这一点早就考虑到了,首先来说传递数据的问题,我们通常需要传递的是一个Bean对象,我们如何来封装传递呢?
其实处理起来很简单,我们直接传递这个Bean对象就可以了,如下代码:
//事件发送的时候直接传递获取到的bean参数
EventBus.getDefault().post(bean);
/**
*@param bean 跟以上代码一样,这里需要接收的就是Bean类型的对象了
*/
@Subscribe
public void changeText(Bean bean){
}
下面需要考虑的就是线程的问题了,获取数据以及发送事件很多时候就在子线程,而我们获取到事件之后的回调我们想给他指定线程,通过threadMode 就能指定回调所在的线程:
/**
* @Subscribe 这个注解就相当于指定接收到事件之后该方法被调用
* threadMode : 指定该方法的回调所在的线程,目前有4种线程类型:
* ThreadMode.MAIN : UI线程
* ThreadMode.POSTING : 事件发出所在的线程,如果事件发出的时候在UI线程,那么该方法就在UI线程中执行,如果在子线程,那么这个方法也会在子线程中执行
* ThreadMode.BACKGROUND : 子线程 如果事件发出的线程是UI线程,那么会在一个新的子线程中执行,如果本来就是在子线程中则直接在该子线程中执行
* ThreadMode.ASYNC :无论事件发出在哪个线程,一定会新建一个子线程执行
*
* @param text 这个参数就是事件源发出事件传递过来的值
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void changeText(Bean bean){
}
3、粘性事件篇
首先说一下什么是粘性事件,就相当于一个女生,当她喜欢上你了之后就会粘着你,除非你严厉的拒绝了她,否则她就一直在你身边,你有什么事她都会知道。
在代码里面的体现是什么呢?
当使用代码发出一个粘性事件之后,这个事件就会被保存起来,只要注册这个事件,这个粘性事件就会知道,然后调用你所写的回调方法。效果如下:
Fragment1中的代码:
mButton.setText("点我发送粘性事件");
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().postSticky("粘性事件发送了");
}
});
Fragment2中的代码:
mButton.setText("点我注册粘性事件");
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().register(Fragment2.this);
}
});
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void changeText(String text) {
mButton.setText(text);
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
}
看效果可以看出是先发送事件然后在注册,但是还是接收到了这个事件。
这里的粘性事件是指发送事件之后,该事件就会被EventBus保存起来,之后只要有人订阅该事件,就会回调订阅的方法。
在上面代码中有 sticky = true 这个赋值操作,这句代码的意思就是订阅方法可以接収粘性事件。但是当发出粘性事件的时候会回调一次(只有先订阅之后再postSticky才会调用)订阅者的方法,不管有没有写sticky = true这行代码。这个大家可以自己测试一下。
(该文章中提到的所有EventBus都是指EventBus3.0,至于原因下篇博客会说明)
这篇博客就介绍到这里。下一篇博客介绍EventBus的原理以及源码。
|
|