通常多pane的设计中,比如Fragment A是个Headline,Fragement B是detail,那么B通常需要实现A的点击事件的接口,这样子的话,两个fragment就高耦合了,而且需要在Fragment A中编写一个interface,如果Fragment很多,情景更复杂些,就乱了。
这里可以使用EventBus这个框架,一个典型的发布者-订阅者模式。具体可以参考:
https://github.com/greenrobot/EventBus
使用方法大致如下:
这个例子来源于Android Developers的一个典型的多Fragment的例子,左边Fragment是HeadlineFragment,含有很多标题的listview,右边是DetailFragment,点击左边Fragment中一项会刷新右边的Fragment。
a. 首先定义自己的Event,这里其实是随便写个类,例子中Headline需传一个点击时候的listview的position给Detail fragment,所以可以写个包装int类型的MessageEvent:
public class MessageEvent {
public int position;
public MessageEvent(int position) {
this.position = position;
}
}
b. 在订阅者(即Detail fragment或者说fragment B)中,onstart和onstop要注册/解注册:
//DetailFragment.java
@Override
public void onStart() {
super.onStart();;
EventBus.getDefault().register(this);
}
@Override
public void onStart() {
super.onStart();
setNewsCategory(0);
EventBus.getDefault().register(this);
}
c. 在订阅者(即Detail fragment或者说fragment B)中,写一个名字叫onEvent的函数,带回来的参数是MessageEvent类型,这个函数即被调用的方法,等待Headline传过来包装了position数据的MessageEvent对象
//DetailFragment.java
public void onEvent(MessageEvent event){
int index = event.positioin;
// do something using index,比如刷新文章内容
}
d. 在发布者(即Headline Fragment或者说Fragment A)中,在合适的地方执行post方法,即发布出去这个MessageEvent,这里即在HeadLineFragment的listview被点击的回调中发送post:
//HeadLineFragment.java
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
EventBus.getDefault().post(new MessageEvent(position));
}
这样子,DetailFragment的onEvent方法就会被调用,含有position的MessageEvent也就被传了过去,随之DetailFragment根据拿到的position来刷新界面。
大功告成,这里可以发现两个fragment没有写任何的interface也没implements任何的接口,也不用实例化一个listenser并且执行所谓的setonlistener。
这里的内部流程大致是,EventBus在某个组件中注册的时候回记录下这个组件里面的onEvent函数,一个应用中可能有多个onEvent函数等待被调用,这里即通过onEvent函数的参数类型和个数来区别。
使用时需要注意一个问题,这里EventBus是通过java反射机制来找到这个onEvent方法的,所以打包的时候若需要混淆的话千万记住不要混淆onEvent这个函数,可以在proguard文件中添加:
-keepclassmembers class ** {
public void onEvent*(**);
}