观察者模式使用率较高,因为这个模式最重要的作用就是解耦,将观察者和被观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。
观察者模式的定义
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
观察者模式的使用场景
关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
事件多级触发场景。
跨系统的消息交换场景,如消息队列、事件总线的处理机制。
观察者模式简单Demo
import java.util.Observable;
import java.util.Observer;
public class Coder implements Observer {
public static final String TAG = "zy";
public String name;
public Coder(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Log.v(TAG, "Hi, " + name + ", DeTechFrontier更新啦,内容:" + arg);
}
@Override
public String toString() {
return "Coder{" +
"name='" + name + '\'' +
'}';
}
}
package observer.gome.com.observerdemo;
import java.util.Observable;
public class DevTechFrontier extends Observable {
public void postNewPublication(String content) {
//标识状态或内容发生改变
setChanged();
//通知所有的观察者
notifyObservers(content);
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//被观察者角色
DevTechFrontier devTechFrontier = new DevTechFrontier();
//观察者
Coder mrsimple = new Coder("mr.simple");
Coder coder1 = new Coder("coder-1");
Coder coder2 = new Coder("coder-2");
Coder coder3 = new Coder("coder-3");
//将观察者注册到可观察对象的观察者队列中
devTechFrontier.addObserver(mrsimple);
devTechFrontier.addObserver(coder1);
devTechFrontier.addObserver(coder2);
devTechFrontier.addObserver(coder3);
//发布消息
devTechFrontier.postNewPublication("新的一期开发者技术前线周报发布啦!");
}
}
Log分析:
V/zy: Hi, coder-3, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!
V/zy: Hi, coder-2, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!
V/zy: Hi, coder-1, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!
V/zy: Hi, mr.simple, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!
Observer和Obervable是JDK的内置类型,这里的Observer是抽象观察者角色,Coder扮演的是具体观察者角色;Observable对应的是抽象主题角色,DevTechFrontier则是具体主题的角色。Coder是具体的观察者,它们订阅了DevTechFrontier这个具体的可观察对象,当DevTechFrontier有更新时,会遍历所有的观察者(这里是Coder),然后给这些观察者对象发布一个更新消息,即调用Coder的update方法,这样就达到了一对多的通知功能。在整个过程中,通知系统都依赖Oberver和Obervable这些抽象类,因此,对于Coder和DevTechFrontier完全没有耦合,保证了订阅系统的灵活性、可扩展性。
Android中的观察者模式
/**
* Common base class of common implementation for an {@link Adapter} that can be
* used in both {@link ListView} (by implementing the specialized
* {@link ListAdapter} interface) and {@link Spinner} (by implementing the
* specialized {@link SpinnerAdapter} interface).
*/
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);
}
/**
* Notifies the attached observers that the underlying data has been changed
* and any View reflecting the data set should refresh itself.
* //当数据集发生变化,通知所有观察者
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}
由上述代码可知:BaseAdapter是一个观察者模式,BaseAdpater是如何运作的?先到mDataSetObservable.notifyChanged();函数看看:
public class DataSetObservable extends Observable<DataSetObserver> {
/**
* Invokes {@link DataSetObserver#onChanged} on each observer.
* Called when the contents of the data set have changed. The recipient
* will obtain the new contents the next time it queries the data set.
* 调用每一个观察者的onChanged()函数来通知它们 被观察发生了改变。
*/
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
//调用所有观察者的onChanged方法
mObservers.get(i).onChanged();
}
}
}
... ...
}
mDataSetObservable.notifyChanged();中遍历所有的观察者,并且调用它们的onChanged方法,从而告知观察者的变化。
观察者就是ListView通过setAdapter方法设置Adapter产生的。
/**
* Sets the data behind this ListView.
*
* The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
* depending on the ListView features currently in use. For instance, adding
* headers and/or footers will cause the adapter to be wrapped.
*
* @param adapter The ListAdapter which is responsible for maintaining the
* data backing this list and for producing a view to represent an
* item in that data set.
*
* @see #getAdapter()
*/
@Override
public void setAdapter(ListAdapter adapter) {
//如果已经有了一个Adapter,那么先注销Adapter对应的观察者
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
// AbsListView#setAdapter will update choice mode states.
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
//获取数据的数量
mItemCount = mAdapter.getCount();
checkFocus();
//注意这里:创建一个数据集观察者
mDataSetObserver = new AdapterDataSetObserver();
//将这个观察者注册到Adapter中,实际上是注册到DataSetObserverObservable中
mAdapter.registerDataSetObserver(mDataSetObserver);
mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
int position;
if (mStackFromBottom) {
position = lookForSelectablePosition(mItemCount - 1, false);
} else {
position = lookForSelectablePosition(0, true);
}
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
if (mItemCount == 0) {
// Nothing selected
checkSelectionChanged();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
requestLayout();
}
从程序中可以看到,在设置Adapter时会构建一个AdapterDataSetObserver,这就是上面所说的观察者,最后,将这个观察者注册到Adapter中,这样我们的被观察者(Adapter)和观察者(AdapterDataSetObserver)都有了。这个时候可能就有点不明白,AdapterDataSetObserver是什么?它是如何运作的?那么就先来看看AdapterDataSetObserver,AdapterDataSetObserver定义在ListView的父类AbsListView汇总,具体代码如下。
#AbsListView
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
... ...
}
/**
* Should be used by subclasses to listen to changes in the dataset
*/
#AbsListView
AdapterDataSetObserver mDataSetObserver;
#AdapterDataSetObserver 是 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();
}
}
}
AdapterDataSetObserver又继承自父类AdapterView的AdapterDataSetObserver,具体代码如下:
public abstract class AdapterView<T extends Adapter> extends ViewGroup {
... ...
}
#AdapterDataSetObserver 是 AdapterView 的内部类
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
//上文讲过,调用Adapter的notifyDataSetChanged时会调用所有观察者的onChanged方法,核心实现就在这里:
//上文讲过,调用Adapter的notifyDataSetChanged时会调用所有观察者的onChanged方法,核心实现就在这里。
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
//获取Adapter中数据的数量
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();
//重新布局ListView、GridView等AdapterView组件
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;
}
}
//到这里就可以明白了:当ListView数据发生改变时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数又会调用所有观察者(AdapterDataSetObserver ),的onChanged方法,在onChanged函数中又会调用ListView重新布局的函数使得ListView刷新界面,这就是一个观察者模式。
最后整理一下这个过程,AdapterView中有一个内部类AdapterDataSetObserver,在ListView中设置Adapter时会构建一个AdapterDataSetObserver,并且注册到Adapter中,这就是一个观察者。而Adpater中包含一个数据集可观察者DataSetObservable,在数据数量发生变更时,开发者手动调用Adapter.notifyDataSetChanged,而notifyDataSetChanged实际上会调用DataSetObservable的notifyChanged函数,该函数会遍历所有观察者的onChanged函数。在AdapterDataSetObserver的onChanged函数中会获取Adapter中数据集的新数量,然后调用ListView的requestLayout方法进行重新布局,更新用户界面。
《Android源码设计模式》