概念:
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
四个元素(自我定义):
观察者、被观察者、注册时机、方法调用
两种实现方式:
观察者被动接受消息
1.创建被观察者接口
public interface Subject{
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
被观察者的实现逻辑
public class WeatherData implements Subject{
private ArrayList observers;
//温度
private String temperature;
//湿度
private String humidity;
//气压
private String pressure;
public WeatherData() {
observers=new ArrayList();
}
/**
* 订阅
*/
public void registerObserver(Observer o) {
observers.add(o);
}
/**
* 取消订阅
*/
public void removeObserver(Observer o) {
if(observers.indexOf(o)>=0){
observers.remove(o);
}
}
/**
* 通知观察者
*/
public void notifyObservers() {
for(Observer o:observers){
o.update(temperature, humidity, pressure);
}
}
/**
* 数据改变后,通知观察者
* @param temperature
* @param humidity
* @param pressure
*/
public void setNewData(String temperature,String humidity,String pressure){
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
notifyObservers();
}
}
在notifyObservers方法中会遍历观察者集合调用其的update方法,然后传过去变化的值,在观察者中显示。
2.创建观察者接口
public interface Observer{
public void update(String temperature,String humidity,String pressure);
}
3.观察者的实现与注册,每一个观察者的注册时机不同,这里是在实例化观察者的时候注册的
public class CurrentCodition implements Observer {
private Subject weaterData;
public CurrentCodition(Subject weaterData) {
this.weaterData = weaterData;
weaterData.registerObserver(this);
}
@Override
public void update(String temperature,String humidity,String pressure) {
//具体实现逻辑
}
}
4.调用更新
WeatherData weatherData=new WeatherData();
Observer1 observer1=new Observer1(weatherData);
weatherData.setNewData("10", "20", "30");
观察者主动接受消息
1.被观察者
在上文的基础上添加get方法,为了给观察者提供获得想要数据的方法。
public String getTemperature() {
return temperature;
}
public String getHumidity() {
return humidity;
}
public String getPressure() {
return pressure;
}
2.观察者
修改观察者中的update方法,从WeatherData实例中直接获得自己想要的数据,不需要的就不用get了
public void update(Observable o, Object arg) {
if(o instanceof WeatherData){
WeatherData data=(WeatherData)o;
this.humidity=data.getHumidity();
this.pressure=data.getPressure();
this.temperature=data.getTemperature();
}
System.out.println("数据提取完毕,并已展示");
}
在Android中的使用
1.setOnClickListener()实现一对一的观察者模式
首先直接看方法里面是怎么一个实现逻辑
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
可以发现setOnClickListener()的过程中直接将OnClickListener赋值给了ListenerInfo中的变量,然后这个变量什么时候调用呢,接着看
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
可以看到在performClick()方法中直接调用onClick方法,那又是谁调的performClick()方法呢,通过搜索定位到View类中,可以看到以下代码逻辑
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
if (isNestedScrollingEnabled()
&& (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
|| action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
|| action == R.id.accessibilityActionScrollUp
|| action == R.id.accessibilityActionScrollLeft
|| action == R.id.accessibilityActionScrollDown
|| action == R.id.accessibilityActionScrollRight)) {
if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) {
return true;
}
}
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK: {
if (isClickable()) {
performClick();
return true;
}
} break;
case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
if (isLongClickable()) {
performLongClick();
return true;
}
} break;
代码中用了一个switch条件判断,根据不同的操作执行相应的逻辑,看到这里就应该很清楚,View这个被观察者,监听到状态的变化后,就会去调用注册进来的onClickListener中的onClick观察者方法,完成相应的操作,由于是一对一的监测,所以没有集合的遍历操作。
2.listView实现一对多的观察者模式
先看被观察者的实现方式吧
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public boolean hasStableIds() {
return false;
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
从代码中可以看到BaseAdapter并没有直接继承DataSetObservable(被观察者)类,而是通过组合的方式,作为变量使用的。
然后再看观察者
在listView的父类AdapterView中找到观察者的实现类
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
@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();
}
@Override
public void onInvalidated() {
mDataChanged = true;
if (AdapterView.this.getAdapter().hasStableIds()) {
// Remember the current state for the case where our hosting activity is being
// stopped and later restarted
mInstanceState = AdapterView.this.onSaveInstanceState();
}
// Data is invalid so we should reset our state
mOldItemCount = mItemCount;
mItemCount = 0;
mSelectedPosition = INVALID_POSITION;
mSelectedRowId = INVALID_ROW_ID;
mNextSelectedPosition = INVALID_POSITION;
mNextSelectedRowId = INVALID_ROW_ID;
mNeedSync = false;
checkFocus();
requestLayout();
}
public void clearSavedState() {
mInstanceState = null;
}
}
然后看方法的调用
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
每次有数据更新的时候,都会调用这个方法刷新数据,可以看到方法中是遍历一个观察者的集合,然后调用统一的实现方法onChanged()实现数据的刷新。
最后就是注册了,其实每次setAdapter()就是注册的过程,代码就不贴了,感兴趣的小伙伴可以自行查看源码。
!!还是小菜鸟,如若有问题欢迎指出[微笑脸]
喵印~~