一、什么叫观察者?
先理解一个简单的例子:很多购房者都在关注房子的价格变化,每当房子的价格变化时,所有购房者都可以观察得到,实际上购房者都属于观察者。
- 观察者模式的定义:定义对象间一种一对多的依赖关系,使得每当一个对象发生改变,则所有依赖她的对象都会等到通知并被自动更新。
- 使用场景:1、 关联行为场景;2、事件多级触发场景;3、跨系统的消息交互场景,如消息队列、事件总线的处理机制
二、观察者模式实现
在Java.util包中提供了Observable和Observer接口,使用它们即可完成观察者模式。
Observable:需要被观察的类必须继承Observable类。Observable类的常用方法有:
- 1、public void addObserver(Observer o) : 添加一个观察者;
- 2、public void deleteObserver(Observer o):删除一个观察者;
- 3、public void setChanged() ; 被观察者状态发生改变;
- 4、public void notifyObservers(Object args) ; 通知所有观察者状态改变;
Observer:每个观察者都需要实现Observer接口,Observer接口定义如下:
public interface Observer {
/**
*当被观察者发生变化,并调用了notifyObserver方法,就调用该方法
* @param o 被观察者
* @param args 修改的内容
*/
void update(Observable o, Object arg);
}
例:
package sl.com.designmodedemo.observer;
import java.util.Observable;
import java.util.Observer;
/**
* 定义房子为被观察者
*/
class House extends Observable{
private float price ; //定义房子价格
public House(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
setChanged(); //通知变化点
notifyObservers(price); //通知所有观察者价格改变
}
@Override
public String toString() {
return "房子的价格是:" + this.price;
}
}
/**
* 房子价格变化观察者
*/
class HousePriceObserver implements Observer{
private String name ; //观察房子价格变化的人名
public HousePriceObserver(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
if (arg instanceof Float){ //判断参数类型
System.out.println(this.name + " 观察到的价格更改为:" + ((float)arg));
}
}
}
/**
* 测试
*/
public class Test {
public static void main(String args[]){
House house = new House(1000000.0F);
HousePriceObserver observer1 = new HousePriceObserver("观察者A");
HousePriceObserver observer2 = new HousePriceObserver("观察者B");
HousePriceObserver observer3 = new HousePriceObserver("观察者C");
//加入观察者
house.addObserver(observer1);
house.addObserver(observer2);
house.addObserver(observer3);
//输出房子价格
System.out.println(house);
//修改房子价格
house.setPrice(2000000.0F);
System.out.println(house);
}
}
程序运行结果为:
房子的价格是:1000000.0
观察者C 观察到的价格更改为:2000000.0
观察者B 观察到的价格更改为:2000000.0
观察者A 观察到的价格更改为:2000000.0
房子的价格是:2000000.0
从程序运行结果可以发现,多个观察者都在观察着价格的变化,当被观察者房子价格一变化,则所有观察者都会知道;、
三、Android 源码分析
ListView是Android中重要控件之一,而ListView有一个Adapter,通常我们在给ListView的数据进行操作变化后,都会调用Adapter的notifyDataSetChanged()方法,这是为什么呢?下面我们从源码解析:
第一步,跟进notifyDataSetChanged()方法,这个方法定义在android.widget的BaseAdapter中,具体代码如下:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
//数据集观察者
private final DataSetObservable mDataSetObservable = new DataSetObservable();
//代码省略
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
//当数据集变化时,通知所有观察者
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}
从这里应该看出来BaseAdapter就是一个观察者模式,那么BaseAdapter是如何运作的?这些观察者又是什么?下面接着一步一步的分析。
现在先到mDataSetObservalbe.notifyChanged()的源码看看:
public class DataSetObservable extends Observable {
/**
* 调用每个观察者的onChanged函数来通知他们被观察者发生了变化
*/
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
//代码省略
}
这个代码很简单,就是在mDataSetObservable.notifyChanged()中遍历所有的观察者,并且调用他的onChanged()方法,从而告知观察者发生了变化。
那么 这些观察者从哪里来的呢?其实这些观察者是就是ListView在setAdapter方法设置Adapter产生的,我们看相关代码:
@Override
public void setAdapter(ListAdapter adapter) {
//如果已经有了一个Adapter,并且mDataSetObserver不为空
if (mAdapter != null && mDataSetObserver != null) {
//先注销该Adapter的观察者
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
//代码省略
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
//获取数据的数量
mItemCount = mAdapter.getCount();
checkFocus();
//注意这里:创建了一个数据观察者
mDataSetObserver = new AdapterDataSetObserver();
//将这个观察者注册到Adapter中,实际上是注册到DataSetObservable中
mAdapter.registerDataSetObserver(mDataSetObserver);
//代码省略
} else {
//代码省略
}
requestLayout();
}
从程序可以看到,在设置Adapter的时会构建一个AdapterDataSetObserver,这就是上面说的观察者,最后将这个观察者注册到了Adapter,这样我们的被观察者、观察者就都有了;
那么AdapterDataSetObserver是什么?它如何运作?那么现在来看看,AdapterDataObserver定义在ListView的父类AbsListView中,具体代码如下:
class AdapterDataSetObserver extends AdapterView.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
@Override
public void onInvalidated() {
super.onInvalidated();
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
}
它又继承自AbsListView的父类AdapterView的AdapterDataSetObserver,具体代码如下:
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
//调用Adapter的notifyDataSetChanged的时会调用所有观察者的onChanged()方法,核心就是这里
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
// Detect the case where a cursor that was previously invalidated has
// been repopulated with new data.
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
requestLayout();
}
//代码省略
public void clearSavedState() {
mInstanceState = null;
}
}
到这里就知道了,当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged(),这个方法又调用了DataSetObservable的notifyChanged()方法,这个方法会调用所有观察者AdapterDataSetObserver的onChanged(),在onChanged函数中又会调用ListView重新布局的函数和使得ListView刷新界面,这就是一个观察者模式;
现在再整理一下这个过程,AdapterView中又一个内部类AdapterDataSetObserver,在ListView设置Adapter时会构建一个AdapterDataSetObserver,并且注册到Adapter中,这就是一个观察者。而Adapter中有一个数据集被观察者DataSetObservable,在数据数量发生变更时,开发者手动调用Adapter.notifyDataSetChanged(),而notifyDataSetChanged()实际上是调用DataObservable的notifyChanged()方法,该方法会遍历所有的观察者的onChanged()。在AdapterDataSetObserver的onChanged()会获取Adpaer中数据集的新数量,然后调用ListView的requestLayout()方法重新进行布局,更新用户界面。