huangf 2015-04-17
EventBus简介
EventBus是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间、组件与后台线程间的通信。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。
EventBus特点
组件间的通信更加简单;
事件发送者与接受者解耦
在Activity,Fragment和后台线程间工作良好
避免复杂的,错误依赖和生命周期等问题
使你的代码更加简洁;
效率更高;
依赖的库很小(<50k);
在总安装量超过1亿的APP上得到验证;
拥有分发线程,订阅优先级等先进特性。
组成元素
Event:事件
可以是任意类型的对象。
Subscriber:事件订阅者,接收特定的事件
在EventBus中,使用约定来指定事件订阅者以简化使用。即所有事件订阅都都是以onEvent开头的函数,具体来说,函数的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync这四个,这个和ThreadMode有关。
Publisher:事件发布者,用于通知Subscriber有事件发生
可以在任意线程任意位置发送事件,直接调用EventBus的`post(Object)`方法,可以自己实例化EventBus对象,但一般使用默认的单例就好了:`EventBus.getDefault()`,根据post函数参数的类型,会自动调用订阅相应类型事件的函数。
EventBus使用步骤
定义事件
public class MessageEvent { /* Additional fields if needed */ }
注册和注销订阅
@Override protected void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override protected void onStop() { super.onStop(); EventBus.getDefault().unregister(this); }
定义处理方法
public void onEvent(MessageEvent event)
发送事件
EventBus.getDefault().post(new MessageEvent ())
ThreadModes
在Android中,UI上的改变必须在UI线程也就是主线程中完成。另一方面,网络通信或者其他的耗时操作,都必须运行在主线程以为。EventBus可以帮助你处理这些耗时操作并与UI线程同步(不必深入线程间转换,例如使用AsyncTask)。
PostThread
onEvent:如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
// Called in the same thread (default) public void onEvent(MessageEvent event) { log(event.message); }
MainThread
onEventMainThread:如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
// Called in Android UI's main thread public void onEventMainThread(MessageEvent event) { textField.setText(event.message); }
BackgroundThread
onEventBackgroundThread:如果使用onEventBackgroundThread作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackgroundThread就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackgroundThread函数直接在该子线程中执行。
// Called in the background thread public void onEventBackgroundThread(MessageEvent event){ saveToDisk(event.message); }
Async
onEventAsync:使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.
// Called in a separate thread public void onEventAsync(MessageEvent event){ backend.send(event.message); }
订阅优先级和事件分发顺序
你可能希望通过在订阅者注册时设置一个优先级来改变事件的分发顺序。
int priority = 1; EventBus.getDefault().register(this, priority);
在相同的分发线程中,高优先级的订阅者比其他订阅者能更快的收到事件通知,默认优先级为0.
取消事件分发
你也许会在订阅者的事件处理处理方法中通过调用cancelEventDelivery(Object event)来中断事件分发进程。后续的订阅者就不会再收到此事件。
// Called in the same thread (default) public void onEvent(MessageEvent event){ // Process the event ... EventBus.getDefault().cancelEventDelivery(event) ; }
Sticky Event
有些事件携带的信息可能会在事件发布后一段时间能仍然有用。例如,一个事件也许表示某些初始化已经完成。或者你有一些传感器或者定位数据,你希望保存最近的值。你可以使用sticky events而不是实现你自己的缓存。EventBus以确定的类型保存最后一个sticky event事件在内存中。这些sticky event能够分发给订阅者或者供其查询。这样,你就不需要特殊的逻辑去考虑已经存在的可用数据。
这就是说,一个sticky event可能会在一段时间前发布:
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
在此之后,一个新的Activity启动了,使用registerSticky进行注册后,新的Activity会立即获得之前发布的sticky event事件:
@Override public void onStart() { super.onStart(); EventBus.getDefault().registerSticky(this); } public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } @Override public void onStop() { EventBus.getDefault().unregister(this); super.onStop(); }
你也可以通过以下方法获取最近的sticky event:
EventBus.getDefault().getStickyEvent(Class<?> eventType)
实现原理
EventBus实现最主要是regist和post的实现,下面简单说一下两个方法的内容,具体可以通过查看源码深入理解。
Regist
在代码中调用 regist方法后,EventBus会通过java中的反射去扫描所有方法,通过匹配“onEvent”开头的方法得到方法列表。并根据方法的参数类型,保存相关数据到Map中。
Map的key为eventType,也就是参数的类名;
Map的value为List,list中的每一项包含订阅者对象,订阅方法,优先级。
Post
在代码中调用了Post方法后,EventBus会根据post方法的参数类型,去Map中查询,得到匹配的项后,通过反射经行调用。
附录
参考
GitHub:https://github.com/greenrobot/EventBus
http://www.cnblogs.com/angeldevil/p/3715934.html