开发中我们都知道,很多时候要在Activty与Activty间,Activty与Fragment等之间传递数据进行交互,操作起来很不方便,我们以前可能会用到接口回调,或是用观察者模式来实现,或是发广播等等。这们操作不仅仅代码量大,而且代码耦合性高,性能不佳,也不便于维护。例如:两个Fragment之间的通信你会怎么实现? 按照Android官方给的建议的解决方法如下: Communicating with the Activity,思路就是Activity实现某个接口,然后在Fragment-A关联上Activity之后将Activity强转为接口类型,然后在某个时刻Fragment中回调这个接口,然后再从Activity中调用Fragment-B中方法。这个过程是不是有点复杂呢? 如果你也这么觉得,那也就是你继续看下去的理由了。
EventBus基本结构
AndroidEventBus类似于观察者模式,通过register函数将需要订阅事件的对象注册到事件总线中,然后根据@Subcriber注解来查找对象中的订阅方法,并且将这些订阅方法和订阅对象存储在map中。当用户在某个地方发布一个事件时,事件总线根据事件的参数类型和tag找到对应的订阅者对象,最后执行订阅者对象中的方法。这些订阅方法会执行在用户指定的线程模型中,比如mode=ThreadMode.ASYNC则表示该订阅方法执行在子线程中,更多细节请看下面的说明。
private void onEventMainThread(User aUser) {
// code
}
如果你有两个同参数类型的接收函数,并且都要执行在主线程,那如何命名呢 ? 即使你有两个符合要求的函数吧,那么我实际上是添加用户的事件,但是由于EventBus只根据事件参数类型来判断接收函数,因此会导致两个函数都会被执行。AndroidEventBus的策略是为每个事件添加一个tag,参数类型和tag共同标识一个事件的唯一性,这样就确保了事件的精确投递。 这就是AndroidEventBus和greenrobot的EventBus的不同,但是由于本人对greenrobot的EventBus并不是很了解,很可能上述我所说的有误,如果是那样,欢迎您指出。
AndroidEventBus起初只是为了学习,但是在学习了EventBus的实现之后,发现它在使用上有些不便之处,我想既然我有这些感觉,应该也是有同感之人,在开发群里交流之后,发现确实有这样的情况。因此才将正式地AndroidEventBus以开源库的形式推出来,希望能够帮助到一些需要的人。当然,这个库的成长需要大家的支持与测试,欢迎大家发 pull request。如果你需要的是一个相对稳定的库,greenrobot的EventBus和square的otto都是非常好的选择。
1. 注册事件接收对象
public class YourActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
// 注册对象
EventBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
// 不要忘记注销!!!!
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
2. 通过Subscriber注解来标识事件接收对象中的接收方法
public class YourActivity extends Activity {
// code ......
// 接收方法,默认的tag,执行在UI线程
@Subcriber
private void updateUser(User user) {
Log.e("", "### update user name = " + user.name);
}
// 含有my_tag,当用户post事件时,只有指定了"my_tag"的事件才会触发该函数,执行在UI线程
@Subcriber(tag = "my_tag")
private void updateUserWithTag(User user) {
Log.e("", "### update user with my_tag, name = " + user.name);
}
// 含有my_tag,当用户post事件时,只有指定了"my_tag"的事件才会触发该函数,
// post函数在哪个线程执行,该函数就执行在哪个线程
@Subcriber(tag = "my_tag", mode=ThreadMode.POST)
private void updateUserWithMode(User user) {
Log.e("", "### update user with my_tag, name = " + user.name);
}
// 含有my_tag,当用户post事件时,只有指定了"my_tag"的事件才会触发该函数,执行在一个独立的线程
@Subcriber(tag = "my_tag", mode = ThreadMode.ASYNC)
private void updateUserAsync(User user) {
Log.e("", "### update user async , name = " + user.name + ", thread name = " + Thread.currentThread().getName());
}
}
User类大致如下 :
public class User { String name ; public User(String aName) { name = aName ; } }
接收函数使用tag来标识可接收的事件类型,与BroadcastReceiver中指定action是一样的,这样可以精准的投递消息。mode可以指定目标函数执行在哪个线程,默认会执行在UI线程,方便用户更新UI。目标方法执行耗时操作时,可以设置mode为ASYNC,使之执行在子线程中。
3. 在其他组件,例如Activity, Fragment,Service中需要发布事件的地方写如下的代码就可以了:
EventBus.getDefault().post(new User("android"));
// post a event with tag, the tag is like broadcast's action
EventBus.getDefault().post(new User("mr.simple"), "my_tag");
发布事件之后,注册了该事件类型的对象就会接收到响应的事件.