前言:1.在做项目的过程中很多地方都有用到观察者模式,不过都是系统封装好的,或者是别人的框架,比如系统的广播,网上比较流行的EventBus事件总线其内部原理都是对观察者模式的具体实现;还有Android中的大部分名为notifyDataSetChange方法的调用,其内部实现也是观察者模式,没错,listView和GridView常用的适配器中就有此方法,我们常用来提醒listview和gridview刷新界面显示。
一:系统的简单实现:
其实Android系统中最简单的观察者模式的实现是Observable(抽象类),Observer(接口),代码都比较少如下:
Observable(抽象类——被观察者):内部维护了一个装有所有观察它的观察者对象集合(list),当本身内容变化时,就遍历集合调用每个观察者对象的update方法
public class Observable {
List<Observer> observers = new ArrayList<Observer>();//维护的所有观察者对象的集合,每个Observer都是一个观察者
boolean changed = false;
public Observable() {//空构造
}
public void addObserver(Observer observer) { // 将一个观察者Observer添加到观察者集合(list)中
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!observers.contains(observer))
observers.add(observer);
}
}
protected void clearChanged() {
changed = false;
}
public int countObservers() {
return observers.size();
}
public synchronized void deleteObserver(Observer observer) { // 将一个观察者Observer从观察者集合(list)中移除
observers.remove(observer);
}
public synchronized void deleteObservers() {// 移除所有的观察者
observers.clear();
}
public boolean hasChanged() {
return changed;
}
public void notifyObservers() {//提现所有观察者自身发生了变化,转调用带参数的同名函数notifyObservers
notifyObservers(null);
}
@SuppressWarnings("unchecked")
public void notifyObservers(Object data) { //真正的遍历集合提醒每一个观察者自身发生了变化,并传递参数,调用每个观察者的update方法
int size = 0;
Observer[] arrays = null;
synchronized (this) {
if (hasChanged()) {
clearChanged();
size = observers.size();
arrays = new Observer[size];
observers.toArray(arrays);
}
}
if (arrays != null) {
for (Observer observer : arrays) {
observer.update(this, data);
}
}
}
protected void setChanged() {
changed = true;
}
}
Observer(接口——观察者) 实现了该接口的子类调用被观察者Observable的addObserver方法,将自身加入到被观察者维护的所有观察者集合中(list),注销(反注册)的时候调用被观察者Observable的deleteObserver方法将自身从list集合中移除。
public interface Observer {
//该接口中只有一个方法
void update(Observable observable, Object data);
}
二 :系统中的观察者模式
Android的四大组件内容提供者,广播,列表展示中常用的BaseAdapter,不都是观察者模式的不同实现吗,原理大致相同,Api的都有类似性,比如register方法对应addObserver方法,unregister对应deleteObserver方法,一般都和Activtiy的生命周期绑定调用;
三:自己写个小Demo 写一个更简单的MyObservable(被观察者),MyObserver(观察者)
Myobservable (抽象类——被观察者)
public abstract class MyObservable {
private static MyObservable mMyObservable;
private ArrayList<MyObserver> mObservaleList;
private MyObservable() {
mObservaleList = new ArrayList<MyObserver>();
}
// 做成单例模式
public final static MyObservable newInstance() {
if (mMyObservable == null) {
mMyObservable = new MyObservable();
}
return mMyObservable;
}
// 注册
public void registerObserver(MyObserver observer) {
if (!mObservaleList.contains(observer)) {//如果没有注册过
mObservaleList.add(observer);
}
}
// 反注册
public void unRegisterObserver(MyObserver observer) {
if (mObservaleList.contains(observer))
mObservaleList.remove(observer);
}
public void notifyDataSetChange(Object data) {
if (mObservaleList != null) {
for (MyObserver observer : mObservaleList) {
observer.update(this, data);
}
}
}
}
MyObserver (接口——观察者)
public interface MyObserver {
void update(MyObservable myObservable,Object data);
}
四:结合fragment的具体应用:
先看下效果:
MainActivity
public class MainActivity extends AppCompatActivity implements MyObserver {
private MyObservable mMyObservable;
private TextView mReceiveText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mReceiveText = (TextView) findViewById(R.id.btn_receiver);
Button btn_next = (Button) findViewById(R.id.btn_next);
btn_next.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, FragmentActivity.class);
startActivity(intent);
}
});
mMyObservable = MyObservable.newInstance();//被观察者对象
mMyObservable.registerObserver(this);//观察者注册
}
@Override
public void update(MyObservable myObservable, Object data) {
Toast.makeText(this,"MainActivity被提醒了",Toast.LENGTH_SHORT).show();
mReceiveText.setText("我已接收到提醒了,收到内容为:"+(String)data.toString());
}
@Override
protected void onDestroy() {
super.onDestroy();
mMyObservable.unRegisterObserver(this);//观察者移除观察
}
}
FragmentActivity
public class FragmentActivity extends android.support.v4.app.FragmentActivity implements FragmentDemo.ClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment);
}
@Override
public void click(String str) {
Toast.makeText(this, "fragment中输入不为空时我在Activity中接收到了内容:"+str, Toast.LENGTH_SHORT).show();
}
}
FragmentDemo(自定义fragment)
public class FragmentDemo extends Fragment {
private ClickListener mClickListener;
private EditText et_input;
public interface ClickListener {
void click(String str);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getActivity() instanceof ClickListener) {
mClickListener = (ClickListener) getActivity();
}
Log.i("fragmentDemo-Life cycle", "onCreate");
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("fragmentDemo-Life cycle", "onCreateView");
View view = inflater.inflate(R.layout.fragmentdemo, container, false);
Button btn_notify = (Button) view.findViewById(R.id.btn_notify);
et_input = (EditText) view.findViewById(R.id.et_input);
Button btn_click = (Button) view.findViewById(R.id.btn_click);
/**
*fragment与宿主之间的交互,比如我们点击fragment中的控件时,我们要将一些操作,或则数据回传到宿主Activity做一些执行,这里一般有2中方法;
* 1.在Activity中直接写一个方法method,在fragment中直接调用getActivity(),方法拿到Activity实例直接调用Activity中的method方法。
* 2.在fragment中写一个接口,接口里有一个方法method,让他的宿主activity去实现接口并重写method方法
* 当然这2种方法哪种较好呢,当然是第二种了,熟悉fragment的同学都知道,fragment出现的一个原因就是可以复用,如果我们用第一种方法写的话,我们直接在
* fragment中调用getActiviy(),在调用method方法,那如果我们在ActivityA,ActivityB,ActivityC中都调用用到了fragment,那我们能保证每个Activity中都有
* method方法吗,这样还得做一个fiagment.getActivity() instanceof 目标Activity ;这样写不解耦,不复用;
*/
btn_click.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str = et_input.getText().toString();
if (!TextUtils.isEmpty(str)) {
if (mClickListener != null)
mClickListener.click(str);
}
}
});
btn_notify.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str = et_input.getText().toString();
if (!TextUtils.isEmpty(str)) {
MyObservable.newInstance().notifyDataSetChange(str);
}
}
});
return view;
}
}
五:个人总结:
个人觉得观察者模式的核心同我们简单的接口调用一本样,只是我们常用的接口调用的时候常用setXXXXX方法设置一个监听,当监听到的时候我们给设置了监听的
一个
对象一个回调方法,而观察者模式只是将
多个
监听对象放到了一个集合里,当变化时给所有的监听对象都回调一下