一、問題的提出
舉例:
WeatherData是氣象站獲取數(shù)據(jù)的對象,通過他獲取到數(shù)據(jù)后更新到不同的布告板上。
WeatherData有三個方法:getTemperature(), getHumidity(), getPressure()用于獲取溫度,濕度,氣壓值
當新數(shù)據(jù)獲得后,可以調(diào)用WeatherData中的measurementsChanged()方法,更新到不同的布告板上。
錯誤的設計:

二、初步認識
首先看看報紙的訂閱是如何進行的:
1、報社的業(yè)務是出版報紙
2、向某家報社訂閱報紙,只要他們有新報紙出版,就給你送來,只要你是他們的訂戶,就會一直收到新報紙
3、當你不想再看報紙時,取消訂閱,他們就不會再送新報紙了
4、只要報社還在運營,就會一直有人向他們訂閱報紙或取消訂閱
出版者(被觀察者Subject) + 訂閱者(觀察者Observe) = 觀察者模式

觀察者模式--在對象之間定義了一對多的依賴,這樣一來,當一個對象改變狀態(tài),依賴它的對象會收到通知并自動更新。

三、模式類圖

四、優(yōu)點
觀察者模式提供了一種對象設計,讓被觀察者和觀察者之間松耦合,他們可以交互,但是不需要知道彼此的細節(jié),被觀察者只需要知道觀察者實現(xiàn)了Oberver接口,并不需要知道觀察者的具體類是誰,做了什么細節(jié)操作。因為被觀察者唯一依賴的是一個實現(xiàn)Observer接口的對象列表,所以可以隨時增加觀察者,也可以用新的觀察者取代現(xiàn)有的觀察者,刪除觀察者。當有新的觀察者出現(xiàn)時,無需修改被觀察者代碼,被觀察者只把消息發(fā)送給觀察者,觀察者如何處理,被觀察者并不關(guān)心。
Tips:
松耦合的設計能讓我們建立有彈性的OO系統(tǒng),能應對變化,對象之間的相互依賴降到了最低。
五、解決最初氣象站的問題
1、首先建立被觀察者Subject接口,用于注冊、刪除、通知觀察者

2、在WeatherData中實現(xiàn)被觀察者Subject接口

3、建立布告板實現(xiàn)觀察者Observer接口(有多個布告板(觀察者),實現(xiàn)的方法類似)

六、觀察者模式在android中的應用
1、通常在ListView的內(nèi)容變化時,會調(diào)用notifyDataSetChanged()這個方法,然后ListView里面的數(shù)據(jù)就會進行更新。感覺像是觀察者模式,具體是不是再看看源碼。
package android.widget;
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();
}
......
}
這是一個觀察者模式,里面提供了注冊和注銷觀察者以及通知觀察者的方法。
這些方法是通過DataSetObservable這個類調(diào)用的:
package android.database;public class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
......
}
這個類繼承自Observable,Observable中有一個protected final ArrayList<T> mObservers = new ArrayList<T>();,用來保存注冊的觀察者。mDataSetObservable.registerObserver(observer)和mDataSetObservable.unregisterObserver(observer)分別就是增加和刪除。
在notifyChanged方法中,循環(huán)這個集合,調(diào)用每一個觀察者的onChanged()方法。
那么ListView和Adapter什么時候成了訂閱關(guān)系。
在ListView的setAdapter()中
public class ListView extends AbsListView {
public void setAdapter(ListAdapter adapter) {
//如果已經(jīng)有了一個adapter,注銷這個adapter之前的觀察者,
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
......
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
//將新的adapter賦給mAdapter
mAdapter = adapter;
}
......
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
//保存之前的數(shù)據(jù)個數(shù)
mOldItemCount = mItemCount;
//獲取新的個數(shù)
mItemCount = mAdapter.getCount();
checkFocus();
//創(chuàng)建數(shù)據(jù)集觀察者
mDataSetObserver = new AdapterDataSetObserver();
//注冊觀察者
mAdapter.registerDataSetObserver(mDataSetObserver);
...
}
} else {
...
}
requestLayout();
}
}
AdapterDataSetObserver是ListView的父類AbsListView的內(nèi)部類
package android.widget;
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
······
}
}
AdapterDataSetObserver是AdapterView.AdapterDataSetObserver的子類,所以要看super.onChanged()
package android.widget;
public abstract class AdapterView<T extends Adapter> extends ViewGroup {
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();
}
......
}
}
整理一下:當ListView數(shù)據(jù)變化時,調(diào)用Adapter的notifyDataSetChange方法,這個方法調(diào)用DataSetObservable的notifyChanged方法,這個方法又會調(diào)用所有觀察者的onChanged方法,onChanged再調(diào)用重新布局View的方法,完成刷新數(shù)據(jù)的功能。