Android 設計模式情景分析——觀察者模式
觀察者模式是一種使用頻率非常高的模式,有時也被稱作發布/訂閱模式,屬於行為型模式,它最常用的是 GUI 系統、訂閱——發布系統,它一個重要作用就是解耦,使得它們之間的依賴性更小。觀察者模式定義了對象間一種一對多的依賴關系,使得每當一個對象改變狀態時,則所有依賴於它的對象都會得到通知並被自動更新。
1.觀察者模式的使用情景
關聯行為場景;事件多級觸發場景;跨系統的消息交換場景(如消息隊列、事件總線的處理機制)。
2.程序中使用觀察者模式的優缺點
- | 觀察者模式 |
---|---|
優點 | 觀察者和被觀察者之間是耦合抽象,應對業務變化;增強了系統靈活性、可擴展性。 |
缺點 | 開發調試變的比較復雜,Java中消息的通知是順序執行,一個消息的卡頓會影響整體的執行效率,所以使用觀察者模式還需要結合異步操作的方式。 |
3.觀察者模式的UML類圖
Subject:抽象主題,被觀察(Observable)的角色;ConcreteSubject:具體主題;Observer:抽象觀察者;ConcreteObserver:具體的觀察者。
4.觀察者模式的實現
觀察者 Observer 和被觀察者 Observable 是 JDK 中的內置類型。
1.創建觀察者:
public class MyObserver implements Observer {
private String name;
public MyObserver(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(name + ", update:" + arg);
}
}
3.編寫測試方法:
@Test
public void test() throws Exception {
// 被觀察者
MyObservable observable = new MyObservable();
// 觀察者
MyObserver observer1 = new MyObserver("test1");
MyObserver observer2 = new MyObserver("test2");
MyObserver observer3 = new MyObserver("test3");
MyObserver observer4 = new MyObserver("test4");
// 將觀察者註冊到被觀察者對象的觀察者列表中
observable.addObserver(observer1);
observable.addObserver(observer2);
observable.addObserver(observer3);
observable.addObserver(observer4);
// 發布消息
observable.postNewPublication("new");
}
輸出結果:
test4, update:new
test3, update:new
test2, update:new
test1, update:new
可以看到所有訂閱了被觀察者的觀察者都接收到了更新消息,一對多的訂閱——發布系統就完成了。
5.Android系統源代碼中的應用情景
1.notifyDataSetChanged() 方法
我們在使用 ListView 添加數據後,都會調用 Adapter 的 notifyDataSetChanged() 方法來動態更新數據。
notifyDataSetChanged() 方法被定義在 BaseAdapter 中,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();
}
// 代碼省略
}
我們跟進查看 mDataSetObservable.notifyChanged() 方法:
public class DataSetObservable extends Observable<DataSetObserver> {
// 調用每個觀察者的 onChanged() 方法來通知它們被觀察者發生了變化
public void notifyChanged() {
synchronized(mObservers) {
// 調用所有觀察者的 onChanged() 方法
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
// 代碼省略
}
這段代碼就是在 mDataSetObservable.notifyChanged() 中遍歷所有觀察者,並且調用它們的 onChanged() 方法,從而告知觀察者發生了變化。
那麽這些觀察者是哪裏來的呢?其實是 ListView 通過 setAdapter() 方法設置 Adapter 產生的,我們來看看相關代碼:
public class ListView extends AbsListView {
// 代碼省略
@Override
public void setAdapter(ListAdapter adapter) {
// 如果已經有了一個 Adapter,那麽先註銷該 Adapter 對應的觀察者
if (mAdapter != null && mDataSetObserver != null) {
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 中。
到這裏,我們就知道了,當 ListView 的數據發生變化時,調用 Adapter 的 notifyDataSetChanged() 方法,這個方法又調用 DataSetObservable 的 notifyChanged() 方法,這個方法又調用所有觀察者(AdapterDataSetObserver)的 onChanged() 方法,在 onChanged() 方法中又會調用 ListView 重新布局的方法使得 ListView 刷新界面,這就是一個觀察者模式。
Android 設計模式情景分析——觀察者模式