Otto框架是square公司为Android出的一款事件总线框架,主要是为了解决大项目中耦合性过高的问题,比如涉及到多个类都需要响应某一个操作,原始的做法就是使用广播,事件产生者发送广播,事件订阅者接收广播,并作出相应的操作,但是这样在项目越来越大后,就越来越不好维护和扩展,所以我们引进Otto这款框架,类似的还有一个Event Bus,Otto相比后者优势主要是上手什么简单,缺点是性能上会有一点差距,如果不在乎那一点差距完全可以使用Otto。
Github上有Otto的源码,十分的简洁,算上注解才9个类,实现的方式主要是依赖反射和注解,Otto上有两个注解,一个是Produce,一个是Subscribe。前面是事件产生者,后面是事件订阅者。当在一个方法中post一个事件时,会通过反射查找有Subsribe注解的类并进行调用。
那有人可能会问了,通过广播的方式传值可以通过Bundle和Intent进行传值,那么Otto如何传值呢?
作为一个成熟的框架肯定考虑到了这个问题,Otto中使用bus.post方法进行事件发布,参数是一个Object对象,只有一个参数,但是我们可以通过中间件的形式,比如传入一个javabean对象,中间包裹着参数,然后在订阅者中通过get方法得到值。
话说了这么久,还是先来看看实际的使用,因为是demo,就写的比较简单了,需求如下图
上面的按钮与下面的textview不在一个类中,现在的需求是通过点击上面的按钮使下面的textview动态加载数据,用惯了广播的方式,现在我们用otto框架来实现这个效果,开发效率十分的快。写的时候需要导入otto的jar包。
首先我们建一个BusProvider的类,这个是必须的,为了在类中获取Bus对象,并进行注册。为了让设置UI这样的只能在UI线程中使用的方法在任意线程可以使用,我们使用单例模式建立BusProvider(官方推荐单例方式),并覆写post方法,进行判断如果不是UI线程就通过handler进行发送。
BusProvider.java
public class BusProvider extends Bus{
/**
* 通过单例模式返回唯一的bus对象,而且重写父类的post方法,通过handler实现任意线程可以调用
*/
private Handler mHandler = new Handler(Looper.getMainLooper());
private static Bus bus = new BusProvider();
private BusProvider(){
}
public static Bus getInstance(){
return bus;
}
@Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
super.post(event);
}else {
mHandler.post(new Runnable() {
@Override
public void run() {
BusProvider.super.post(event);
}
});
}
}
}
然后我们就能通过单例模式获取bus的对象,并进行注册使用,这次实现的功能是动态传用户名和密码,并在textview中显示,我们需要先写一个中间的bean类
UserInfo.java
public class UserInfo {
public String username;
public String password;
public UserInfo(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
topfragment.java
public class TopFragment extends Fragment implements OnClickListener {
private View view;
private Button button1;
private Button button2;
private Button button3;
private Button button4;
private Bus bus;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
bus = BusProvider.getInstance();
bus.register(this);
view = inflater.inflate(R.layout.frag_top, container, false);
initView();
initEvent();
return view;
}
private void initEvent() {
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
}
private void initView() {
button1 = (Button) view.findViewById(R.id.button1);
button2 = (Button) view.findViewById(R.id.button2);
button3 = (Button) view.findViewById(R.id.button3);
button4 = (Button) view.findViewById(R.id.button4);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
bus.post(new UserInfo("admin","admin"));
break;
case R.id.button2:
bus.post(new UserInfo("user","123456"));
break;
case R.id.button3:
bus.post(new UserInfo("32525","abc"));
break;
case R.id.button4:
bus.post(new UserInfo("asdasd","25252"));
break;
}
}
}
bottomfragment.java
public class BottomFragment extends Fragment{
private View view;
private TextView mTextView;
private Bus bus;
@Override
public void onAttach(Activity activity) {
bus = BusProvider.getInstance();
bus.register(this);
super.onAttach(activity);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.frag_bottom, container, false);
mTextView = (TextView) view.findViewById(R.id.bottom_text);
return view;
}
@Subscribe
public void setText(UserInfo textstring) {
String user = textstring.getUsername();
String psd = textstring.getPassword();
StringBuffer buffer = new StringBuffer();
buffer.append("username:").append(user).append(" password:").append(psd);
mTextView.setText(buffer);
}
}
源码已上传github,地址:https://github.com/sheepm/otto_demo