时间过得很快,转眼迎来了清明小长假,在小长假到来前期搞定了一个问题,心里还是很高兴的,这里分享给大家,希望大家遇到相同问题时能有有所帮助。
先说一下我的需求吧,在手头的项目里有这么一个需求,就是一个activity,它有三个fragment,activity要通过网络从服务端获取数据,然后分发给三个fragment展示。
最初,我是想用broadcastReceiver实现的,但是写了一堆代码以后发现不是想象的那么简单。当activity获取到数据后发送广播,此时FragmentA和FragmentB已经初始化完毕,当然也完成了BroadcastReceiver的注册,这两个是可以接受到activity传递过来的数据的,但是FragmentC就尴尬了,在activity发送广播的时候它还没有初始化,也就没有注册广播接收器,自然也就没有数据展示了。这个问题让我很是头大了一会儿,后来考虑的用一下EventBus试试,结果一试还真成了,哈哈哈哈,先让我笑几声,然后在这里记录一下EventBus的使用吧。
首先,添加依赖库:
Androidstudio的gradle配置如下:
compile 'org.greenrobot:eventbus:3.0.0'
然后,定义一个MessageEvent类:
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
第三,在三个Fragment中注册、订阅事件:
public class FragmentA extends Fragment {
private static final String TAG = "FragmentA";
private TextView tvAAA;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_aa,container,false);
tvAAA=view.findViewById(R.id.text_a);
Log.d(TAG, "onCreateView: ");
//注册
EventBus.getDefault().register(this);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView: ");
//注销
EventBus.getDefault().unregister(this);
}
}
第四,事件订阅者处理事件。这里多说几句,如果是普通的事件,无法实现刚开始说的事件先发送,后注册获取的效果,所以这里使用的是EventBus 的 黏性事件,这个可以非常好的达到我们的要求。
//事件订阅者处理事件,必须有此方法
//这里我们的ThreadMode设置为MAIN,事件的处理会在UI线程中执行,用TextView来展示收到的事件消息
//注意,这里的注解里必须有sticky,并将值设置为true,表示与事件绑定,可以在事件已经发送但是还没有注册的情况下,一旦注册,就可以接受到数据
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void onResult(MessageEvent messageEvent){
tvAAA.setText(messageEvent.getMessage());
}
最后,发送黏性事件:
private void sendMsg() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
runOnUiThread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().postSticky(new MessageEvent("here is activity"));
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
简单的几行代码就实现了我们的要求是不是感觉so easy,不过效果虽然实现了,但是我们真正懂得了EventBus了吗,未必!下面大概了解一下EventBus:
EventBus的三要素
EventBus有三个主要的元素需要我们先了解一下:
- Event:事件,可以是任意类型的对象。
- Subscriber:事件订阅者,在EventBus3.0之前消息处理的方法只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,他们分别代表四种线程模型。而在EventBus3.0之后,事件处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(默认为POSTING),四种线程模型下面会讲到。
- Publisher:事件发布者,可以在任意线程任意位置发送事件,直接调用EventBus的post(Object)方法。可以自己实例化EventBus对象,但一般使用EventBus.getDefault()就好了,根据post函数参数的类型,会自动调用订阅相应类型事件的函数。
EventBus的四种ThreadMode(线程模型)
EventBus3.0有以下四种ThreadMode:
- POSTING(默认):如果使用事件处理函数指定了线程模型为POSTING,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
- MAIN:
事件的处理会在UI线程中执行。事件处理时间不能太长,长了会ANR的。 - BACKGROUND:如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
- ASYNC:无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行,同样,此事件处理函数中禁止进行UI更新操作。