一、什么叫觀察者?
先理解一個(gè)簡(jiǎn)單的例子:很多購(gòu)房者都在關(guān)注房子的價(jià)格變化,每當(dāng)房子的價(jià)格變化時(shí),所有購(gòu)房者都可以觀察得到,實(shí)際上購(gòu)房者都屬于觀察者。
- 觀察者模式的定義:定義對(duì)象間一種一對(duì)多的依賴(lài)關(guān)系,使得每當(dāng)一個(gè)對(duì)象發(fā)生改變,則所有依賴(lài)她的對(duì)象都會(huì)等到通知并被自動(dòng)更新。
- 使用場(chǎng)景:1、 關(guān)聯(lián)行為場(chǎng)景;2、事件多級(jí)觸發(fā)場(chǎng)景;3、跨系統(tǒng)的消息交互場(chǎng)景,如消息隊(duì)列、事件總線的處理機(jī)制
二、觀察者模式實(shí)現(xiàn)
在Java.util包中提供了Observable和Observer接口,使用它們即可完成觀察者模式。
Observable:需要被觀察的類(lèi)必須繼承Observable類(lèi)。Observable類(lèi)的常用方法有:
- 1、public void addObserver(Observer o) : 添加一個(gè)觀察者;
- 2、public void deleteObserver(Observer o):刪除一個(gè)觀察者;
- 3、public void setChanged() ; 被觀察者狀態(tài)發(fā)生改變;
- 4、public void notifyObservers(Object args) ; 通知所有觀察者狀態(tài)改變;
Observer:每個(gè)觀察者都需要實(shí)現(xiàn)Observer接口,Observer接口定義如下:
public interface Observer {
/**
*當(dāng)被觀察者發(fā)生變化,并調(diào)用了notifyObserver方法,就調(diào)用該方法
* @param o 被觀察者
* @param args 修改的內(nèi)容
*/
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 ; //定義房子價(jià)格
public House(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
setChanged(); //通知變化點(diǎn)
notifyObservers(price); //通知所有觀察者價(jià)格改變
}
@Override
public String toString() {
return "房子的價(jià)格是:" + this.price;
}
}
/**
* 房子價(jià)格變化觀察者
*/
class HousePriceObserver implements Observer{
private String name ; //觀察房子價(jià)格變化的人名
public HousePriceObserver(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
if (arg instanceof Float){ //判斷參數(shù)類(lèi)型
System.out.println(this.name + " 觀察到的價(jià)格更改為:" + ((float)arg));
}
}
}
/**
* 測(cè)試
*/
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);
//輸出房子價(jià)格
System.out.println(house);
//修改房子價(jià)格
house.setPrice(2000000.0F);
System.out.println(house);
}
}
程序運(yùn)行結(jié)果為:
房子的價(jià)格是:1000000.0
觀察者C 觀察到的價(jià)格更改為:2000000.0
觀察者B 觀察到的價(jià)格更改為:2000000.0
觀察者A 觀察到的價(jià)格更改為:2000000.0
房子的價(jià)格是:2000000.0
從程序運(yùn)行結(jié)果可以發(fā)現(xiàn),多個(gè)觀察者都在觀察著價(jià)格的變化,當(dāng)被觀察者房子價(jià)格一變化,則所有觀察者都會(huì)知道;、
三、Android 源碼分析
ListView是Android中重要控件之一,而ListView有一個(gè)Adapter,通常我們?cè)诮oListView的數(shù)據(jù)進(jìn)行操作變化后,都會(huì)調(diào)用Adapter的notifyDataSetChanged()方法,這是為什么呢?下面我們從源碼解析:
第一步,跟進(jìn)notifyDataSetChanged()方法,這個(gè)方法定義在android.widget的BaseAdapter中,具體代碼如下:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
//數(shù)據(jù)集觀察者
private final DataSetObservable mDataSetObservable = new DataSetObservable();
//代碼省略
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
//當(dāng)數(shù)據(jù)集變化時(shí),通知所有觀察者
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}
從這里應(yīng)該看出來(lái)BaseAdapter就是一個(gè)觀察者模式,那么BaseAdapter是如何運(yùn)作的?這些觀察者又是什么?下面接著一步一步的分析。
現(xiàn)在先到mDataSetObservalbe.notifyChanged()的源碼看看:
public class DataSetObservable extends Observable<DataSetObserver> {
/**
* 調(diào)用每個(gè)觀察者的onChanged函數(shù)來(lái)通知他們被觀察者發(fā)生了變化
*/
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
//代碼省略
}
這個(gè)代碼很簡(jiǎn)單,就是在mDataSetObservable.notifyChanged()中遍歷所有的觀察者,并且調(diào)用他的onChanged()方法,從而告知觀察者發(fā)生了變化。
那么 這些觀察者從哪里來(lái)的呢?其實(shí)這些觀察者是就是ListView在setAdapter方法設(shè)置Adapter產(chǎn)生的,我們看相關(guān)代碼:
@Override
public void setAdapter(ListAdapter adapter) {
//如果已經(jīng)有了一個(gè)Adapter,并且mDataSetObserver不為空
if (mAdapter != null && mDataSetObserver != null) {
//先注銷(xiāo)該Adapter的觀察者
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
//代碼省略
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
//獲取數(shù)據(jù)的數(shù)量
mItemCount = mAdapter.getCount();
checkFocus();
//注意這里:創(chuàng)建了一個(gè)數(shù)據(jù)觀察者
mDataSetObserver = new AdapterDataSetObserver();
//將這個(gè)觀察者注冊(cè)到Adapter中,實(shí)際上是注冊(cè)到DataSetObservable中
mAdapter.registerDataSetObserver(mDataSetObserver);
//代碼省略
} else {
//代碼省略
}
requestLayout();
}
從程序可以看到,在設(shè)置Adapter的時(shí)會(huì)構(gòu)建一個(gè)AdapterDataSetObserver,這就是上面說(shuō)的觀察者,最后將這個(gè)觀察者注冊(cè)到了Adapter,這樣我們的被觀察者、觀察者就都有了;
那么AdapterDataSetObserver是什么?它如何運(yùn)作?那么現(xiàn)在來(lái)看看,AdapterDataObserver定義在ListView的父類(lèi)AbsListView中,具體代碼如下:
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
@Override
public void onInvalidated() {
super.onInvalidated();
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
}
它又繼承自AbsListView的父類(lèi)AdapterView的AdapterDataSetObserver,具體代碼如下:
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
//調(diào)用Adapter的notifyDataSetChanged的時(shí)會(huì)調(diào)用所有觀察者的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;
}
}
到這里就知道了,當(dāng)ListView的數(shù)據(jù)發(fā)生變化時(shí),調(diào)用Adapter的notifyDataSetChanged(),這個(gè)方法又調(diào)用了DataSetObservable的notifyChanged()方法,這個(gè)方法會(huì)調(diào)用所有觀察者AdapterDataSetObserver的onChanged(),在onChanged函數(shù)中又會(huì)調(diào)用ListView重新布局的函數(shù)和使得ListView刷新界面,這就是一個(gè)觀察者模式;
現(xiàn)在再整理一下這個(gè)過(guò)程,AdapterView中又一個(gè)內(nèi)部類(lèi)AdapterDataSetObserver,在ListView設(shè)置Adapter時(shí)會(huì)構(gòu)建一個(gè)AdapterDataSetObserver,并且注冊(cè)到Adapter中,這就是一個(gè)觀察者。而Adapter中有一個(gè)數(shù)據(jù)集被觀察者DataSetObservable,在數(shù)據(jù)數(shù)量發(fā)生變更時(shí),開(kāi)發(fā)者手動(dòng)調(diào)用Adapter.notifyDataSetChanged(),而notifyDataSetChanged()實(shí)際上是調(diào)用DataObservable的notifyChanged()方法,該方法會(huì)遍歷所有的觀察者的onChanged()。在AdapterDataSetObserver的onChanged()會(huì)獲取Adpaer中數(shù)據(jù)集的新數(shù)量,然后調(diào)用ListView的requestLayout()方法重新進(jìn)行布局,更新用戶(hù)界面。