Android--Otto事件总线 -- 组件之间通讯框架使用 --模式解析

前言:Otto事件总线 -- 组件之间通讯框架

对于之前的情况activity之间或者fragment之间等跳转传值一般都是用bundle、intent等,从activityA --- activityB用startActivity,用startActivityForResult()可以接受后者回到前者的参数并且可做一些更新UI等操作。这样一来就要判断从A中哪一个按钮跳转到了B,就要设置唯一标识定义什么FRIST=1,FFFFF=2等。Otto事件总线解决了这个问题,只要在订阅事件,接收方接受订阅,传值类型为唯一标示。这样子只要在触发了post后,接受方就会执行指定方法,就算不返回到A界面也是可以执行的。

使用Otto事件总线框架的原因

  1. 一般情况下,在Android中的Activity与Activity之间值的传递,我们通过Intent的方式;
  2. Activity与Fragment之间我们通过setArguments,值回调我们是在Fragment中的onAttach()接口方式实现;
  3. Activity与service之间,我们通常会使用binder机制,但是binder机制实际上使用的也是接口回调的方式;
  4. 在一些比较复杂的情况,比如Activity嵌套多个Fragment页面的时候,如果一个页面的值发生了改变,其他的页面也要跟着发生数据的更新操作,这样我们会频繁的使用接口回调的方式,这种方式的耦合性太高。

Otto事件的模式

对于一个如此方便的框架,Java模式的加入是必不可少的,无论是Rxjava(观察者模式扩展)还是EventBus都有观察者模式,所以中间讲解该模式。

一、简单使用

  • @Subscribe:这个在调用了register后有效,表示订阅了一个事件,并且方法的用 public 修饰的.方法名可以随意取,重点是参数,它是根据你的参数进行判断
  • @Produce注解告诉Bus该函数是一个事件产生者,产生的事件类型为该函数的返回值。

 

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)里。

被观察

被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。

撤销观察

观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。

image

举例子:

这里创建一个抽象观察者(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();

 

image

解绑

subject.unbinding(secondObserver);
        subject.setState(3);
        subject.notifyAllObservers();

 

image

posted on 2018-08-16 09:57  TMusketeer  阅读(614)  评论(3编辑  收藏  举报