一、背景介绍
在编程过程中,当我们想通知其他组件某些事情发生时,我们通常使用观察者模式,正是因为观察者模式非常常见,所以在jdk1.5中已经帮助我们实现了观察者模式,我们只需要简单的继承一些类就可以快速使用观察者模式,在Android中也有一个类似功能的开源库EventBus。 此篇幅主要讲述EventBus是什么?EventBus可以帮助我们干些什么?还有EventBus是怎样调用的?下一篇幅将会对EventBus的源码进行解读,分析EventBus框架结构,工作原理等,敬请关注。
二、EventBus简介
对于Android开发人员来讲,跨线程通信,多个Activity通信,服务和UI通信,组件之间的通信等,并不陌生,Android系统给我们提供了很多便捷的方法,例如广播,Handler,方法回调等。在GitHut上有这么一个开源库EventBus,他很好的解决了以上所述场景的通信,并提供了简化,易懂,低耦合的架构API。
- 什么是EventBus
EventBus其实是利用了这么一个概念,以发布者和订阅者的角色,描述和处理事件的传递,事件传递之间带有事件属性(即数据)。而且这个角色是可以进行对调的,一个发布者可以去发布事件也可以接受事件,一个订阅者可以订阅多个事件也可以发布事件,这样就形成了事件池的事件分发机制,所有发布者发布的事件被存储在对应EventBus的事件池中,所有订阅者根据自己的需要往事件池里注册要订阅的事件,当事件池中有事件进来时,EventBus会根据事件分发原则把事件分发到订阅者去处理。 - EventBus能做什么,怎么调用
首先EventBus是一个开源框架,此框架主要是建立事件分发和订阅的。用来简化应用组件之间的通信,替代传统通信模式:广播,Handler,方法回调,而生的一个轻量级的通信架构,使用者只需要进行注册,订阅,发布,取消订阅,这几个简单的操作既可以完成不同组件之间的通信交流和数据传输。在实际应用开发中,我们总是希望把耗时复杂的工作交给service去处理,在UI组件中只关心结果的展示和用户的交互。在EventBus没出来前,我们可能想到最多的方法可能就是广播,Handler线程通信等等方法来解决,但是无可否认这些传统的处理方法有时候太过于繁琐,而EventBus能更好,更简洁地帮我们解决这些繁琐的问题。至于EventBus怎么调用?下面我们由Demo来讲解。
Demo讲解
例如我们要做一个计时器,希望服务端每一秒通知一下UI端去更新时间信息这么一个需要求。在传统模式下,我们可能需要绑定服务,在服务中调用UI组件进行更新视图,又或者建立回调方法进行通知变更。那么在EventBus中,我们是怎样处理的呢?
- 引入EventBus开源库
- 注册到EventBus
- 订阅事件
- 发布事件
- 反注册EventBus
下面结合Demo的代码进行分析:
先在gradle中添加依赖:
compile 'org.greenrobot:eventbus:3.0.0'
接着看看核心代码:
public class MainActivity extends Activity {
private TextView time;
private Intent tS;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
time = (TextView) findViewById(R.id.time);
EventBus.getDefault().register(this);
tS = new Intent(this, TimeService.class);
startService(tS);
}
public void onEventMainThread(TimeEvent event) {
int h = 0, m = 0, s = 0;
int t = event.getTime();
if (t >= 86400) {
time.setText("24:00:00+");
} else {
if (t >= 3600) {
h = t / 3600;
t = t % 3600;
}
if (t >= 60) {
m = t / 60;
t = t % 60;
}
s = t;
time.setText(h + ":" + m + ":" + s);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
stopService(tS);
}
}
- 要接收事件,那么先要有订阅者,在此示例中订阅者就是主Activity本身,我们要把它注册到EventBus中
EventBus.getDefault().register(this);
通过以上这么一行代码,我们就完成了订阅者的注册,这里默认注册到默认的EventBus当中,也可以通过其他API建立不同的EventBus对象,每个EventBus对象的事件是互不干扰分发的
- 完成注册后,我们要进行事件的订阅,要有事件的订阅,就必须有对应Type的事件,也就是常说的EventModel
public class TimeEvent {
private int time = 0;
public int getTime(){
return time;
}
public void setTime(int t){
time = t;
}
}
由于我们是要做一个计时器,那么事件我们就定义为一个TimeEvent,里面返回秒数信息就可以了。订阅事件其实就是在订阅者中增加以OnEvent开头的public类型的函数方法:
public void onEventMainThread(TimeEvent event) {
int h = 0, m = 0, s = 0;
int t = event.getTime();
if (t >= 86400) {
time.setText("24:00:00+");
} else {
if (t >= 3600) {
h = t / 3600;
t = t % 3600;
}
if (t >= 60) {
m = t / 60;
t = t % 60;
}
s = t;
time.setText(h + ":" + m + ":" + s);
}
}
对应的参数是唯一的时间类型对象,OnEventXXX有几种时间Mode,分别对应PostThread,MainThread,BackgroundThread,Async根据字面意思也很好理解他们分别在那个线程进行工作处理的,默认为PostThread模式,以上我们接受到TimeEvent时,做了一件事件就是在主线程中根据返回的event中的秒数,进行更新UI组件TextView,进行显示。
3.有了订阅者,有了订阅时间,我们就需要一个发布者和发布事件的流程,我们完成计数的操作是早Service中完成的。
public class TimeService extends Service {
private Thread mTime;
private TimeEvent mTimeEvent;
public TimeService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
mTimeEvent = new TimeEvent();
mTime = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
mTimeEvent.setTime(mTimeEvent.getTime() + 1);
EventBus.getDefault().post(mTimeEvent);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
mTime.start();
}
@Override
public void onDestroy() {
super.onDestroy();
mTime.stop();
mTime.destroy();
mTime = null;
}
}
服务开启时,我们启了一个线程进行每秒的计数,并通过:
EventBus.getDefault().post(mTimeEvent);
把事件结果发布到EventBus中分发处理,EventBus会根据已有的订阅者,调度对应的OnEventXX通过订阅者事件结果。
4.当我们一旦不需要订阅了,我们可以通过反注册取消
EventBus.getDefault().unregister(this);