Android--Otto事件总线 -- 组件之间通讯框架使用 --模式解析
前言:Otto事件总线 — 组件之间通讯框架
对于之前的情况activity之间或者fragment之间等跳转传值一般都是用bundle、intent等,从activityA — activityB用startActivity,用startActivityForResult()可以接受后者回到前者的参数并且可做一些更新UI等操作。这样一来就要判断从A中哪一个按钮跳转到了B,就要设置唯一标识定义什么FRIST=1,FFFFF=2等。Otto事件总线解决了这个问题,只要在订阅事件,接收方接受订阅,传值类型为唯一标示。这样子只要在触发了post后,接受方就会执行指定方法,就算不返回到A界面也是可以执行的。
使用Otto事件总线框架的原因
- 一般情况下,在Android中的Activity与Activity之间值的传递,我们通过Intent的方式;
- Activity与Fragment之间我们通过setArguments,值回调我们是在Fragment中的onAttach()接口方式实现;
- Activity与service之间,我们通常会使用binder机制,但是binder机制实际上使用的也是接口回调的方式;
- 在一些比较复杂的情况,比如Activity嵌套多个Fragment页面的时候,如果一个页面的值发生了改变,其他的页面也要跟着发生数据的更新操作,这样我们会频繁的使用接口回调的方式,这种方式的耦合性太高。
Otto事件的模式
对于一个如此方便的框架,Java模式的加入是必不可少的,无论是Rxjava(观察者模式扩展)还是EventBus都有观察者模式,所以中间讲解该模式。
一、简单使用
1-1:添加依赖
dependencies { compile \'com.squareup:otto:1.3.8\' } 或者 //otto事件总线 compile \'com.squareup:otto:+\'
1-2:订阅和取消订阅
bus.register(this); bus.unregister(this); 发布: bus.post(new MessageEvent()); 注解 @Subscribe:这个在调用了register后有效,表示订阅了一个事件,并且方法的用 public 修饰的.方法名可以随意取,重点是参数,它是根据你的参数进行判断 @Produce注解告诉Bus该函数是一个事件产生者,产生的事件类型为该函数的返回值。 最后,proguard 需要做一些额外处理,防止混淆: -keepattributes *Annotation* -keepclassmembers class ** { @com.squareup.otto.Subscribe public *; @com.squareup.otto.Produce public *; }
1-3:otto推荐使用单例模式,保证只有一个实例
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); } }); } } }
1-4:调用 A–>B
@Subscribe
activityA:
/** * Created by 刘志通 on 2018/7/4. */ public class OttoTestOne extends AppCompatActivity { private Bus bus; private Button button,button2; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ottotwo_layout); //订阅 bus = BusProvider.getInstance(); bus.register(this); button = findViewById(R.id.id_two); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(OttoTestOne.this,OttoTestTwo.class); startActivity(intent); } }); } //注解接收String类型 @Subscribe public void setText(String textstring) { button.setText(textstring); Log.e("检测1",textstring+""); } //接收bean类型 @Subscribe public void setText2(EditBean textstring) { button2.setText(textstring.getEdit1()+""+textstring.getEdit2()); Log.e("检测2", textstring.getEdit1()+""+textstring.getEdit2()); } /** * 取消订阅 * */ @Override protected void onDestroy() { BusProvider.getInstance().unregister(this); super.onDestroy(); } }
activityB
/** * Created by 刘志通 on 2018/7/4. */ public class OttoTestTwo extends AppCompatActivity { private Bus bus; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //获取实例 bus = BusProvider.getInstance(); //注册 bus.register(this); setContentView(R.layout.ottoone_layout); Button button=findViewById(R.id.id_btn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /*发送,这里发送的是bean,也可以直接发送String类型的数据,接收则是A中String类型的接收。*/ EditBean editBean=new EditBean(); editBean.setEdit1("ni"); editBean.setEdit2(" hao"); editBean.setTotal(" ma"); bus.post(editBean); } }); } }
@Produce
只要有activity或者fragment跳转到该页面后,事件就会自动产生,然后在订阅处(谁订阅谁改变)更新一些数据。
//获取实例 bus = BusProvider.getInstance(); //注册 bus.register(this); setContentView(R.layout.ottothird_layout); } @Produce public EditBean providerEvent(){ EditBean eventData = new EditBean(); eventData.setEdit1("hello world"); return eventData; } @Override protected void onDestroy() { super.onDestroy(); bus.unregister(this); }
注:A->B中 @Produce模式则是在A中发起事件,也就是所谓的事件产生者,当从A跳转到B后,如果B中有对EditBean有操作的话,就直接触及到A的@Produce方法,并更新一些数据,这和Post比起来,有点简单,因为你都不用再做任何操作,前一个界面就已经更新了,但Post可以控制何时发起事件,点击按钮后或者网络请求成功后直接bus.post(” … “);
二、观察者模式
前言
观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
需要注意:
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
观察者
(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
被观察
被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。
撤销观察
观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。
举例子:
这里创建一个抽象观察者(Observer)和一个被观察者(Subject),然后继承抽象观察者,观察者们通过观察被观察者(Subject)来改变自己。
创建类:
- 抽象观察者(Observer)
- 被观察者(Subject)
2-1:被观察者Subject.java
public class Subject { private List<Observer> observers = new ArrayList<Observer>(); private Observer observer; private int state; //变更情况 public int getState() { return state; } public void setState(int state) { this.state = state; } //绑定 public void binding(Observer observer) { observers.add(observer); } /** * unbinding(注销观察者,有时候在未获取到实例使用) **/ public void unbinding(Observer cls) { if (cls == null) throw new NullPointerException(); observers.remove(cls); } //通知 public void notifyAllObservers() { for (Observer observer : observers) { observer.update(); } } }
这里需要注意的是如果是常规集合是不能直接用remove的,要如下转换再行删除。
Iterator<Observer> iterator = observers.iterator();
2-2:观察者(Observer)
/** * 观察者 * */ public abstract class Observer { protected Subject subject; public abstract void update(); }
2-3:继承Observer
需要注意的是,我这里创建了3个如下类,只粘贴出一个,分别是FirstObserver,SecondObserver,ThirdObserver。
public class FirstObserver extends Observer { public FirstObserver(Subject subject) { this.subject = subject; subject.binding(this);//绑定 } @Override public void update() { //用来更新数据 System.out.println("我是第一个观察者:"+subject.getState()); } }
2-4:测试
在主方法main中 这里是在每个子类的构造方法中加入了绑定,所以,只要创建对象就已经绑定了,无序再次绑定,当然也是可以解绑的。
//加载被观察者 Subject subject = new Subject(); //加载观察者 FirstObserver firstObserver = new FirstObserver(subject); SecondObserver secondObserver = new SecondObserver(subject); ThirdObserver thirdObserver = new ThirdObserver(subject); subject.setState(2); subject.notifyAllObservers();
解绑
subject.unbinding(secondObserver); subject.setState(3); subject.notifyAllObservers();