在介绍观察者模式之前,先补充两个概念:IOC(控制反转)、DIP(依赖倒置)。
依赖倒置(控制反转),是框架设计的核心,因为有了它们会产生框架,框架的核心就是把【不变】的留在框架层次,把【变化】的留在应用层次,然后两个层次之间通过接口来实现沟通,降低耦合。它们两者本质是同样的,只是一个是从原则上面描述,一个是从方式上面描述。
高层框架不应该依赖于底层的实现,底层的实现应该依赖于高层的框
架,高层框架封装不变的部分,把变化的部分留出接口让底层实现,通
过接口来实现高层与底层之间的沟通。在这个沟通的过程中,框架是主
动的(即调用者),而底层的具体应用实现是被动的(被调用者)。
总体来说,依赖倒置与控制反转都是一个意思:依赖于接口编程,将具体的对象之间的关系通过轻量型的接口来分离,框架层通过接口调用应用层的不同实现(此处即框架与应用层解耦),达到反向控制的目的。依赖倒置是原则,控制反转是体现。
一般来说,IOC有两种实现的方式:
(1)继承( Inheritance)+卡隼函数(hook)——在 Template Pattern中使用
(2)委托( Delegation)+卡隼函数(hook)——在Observer模式中使用
百度百科:观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件(通知者)管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
通俗举例:
通俗来说,举古代打仗为例,敌军为数据集合(被观察者),军官为视图(观察者)。那么中间的通知者就是侦察兵,侦察兵在前线侦查敌情的变动,一有风吹草动就会通知军官,然后军官采取相应的方案。这里军官就是观察者,侦察兵就是通知者(不同角度可能角色会转换)。
当一个对象的改变需要通知其它对象的时候,同时他又不知道具体有多
需要相互依赖的实体对象解耦,让他们共同依赖于抽象接口(类别),
这样即使两个具体对象有改动(只要接口没有变),也不会影响到对
方。而且观察者模式可以实现一个通知者,通知多个完全不同的观察
者。
Adapter(适配器),单独本身就是一种模式。但是在Android中,它还有另一个身份————观察者模式中的通知者。
Android里面实现观察者模式是基于组合,而不是继承的。即,观察者和通知者都是镶嵌在ListView和Adapter中,这样的好处是降低了宿主ListView、Adapter与Observer和Observerable的耦合性。
Android里面ListView的观察者模式的开始是下面经典代码:
MyAdapter adapter = new MyAdapter();
listView.setAdapter(adapter);
我们来看看setAdapter中做了什么事:
@Override
public void setAdapter(ListAdapter adapter) {
//解除之前的Observer
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
//清除之前的缓存,重新更新视图集合
resetList();
mRecycler.clear();
//获取通知者引用(Adapter)
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(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();
//注册观察者
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();
}
看了setAdapter源码,里面有两个地方是观察者模式使用的核心:
即:
//获取通知者引用(Adapter)
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
mDataSetObserver = new AdapterDataSetObserver();
//调用通知者的方法注册观察者
mAdapter.registerDataSetObserver(mDataSetObserver);
ListView获取Adapter的通知者引用,然后通过Adapter.registerDataSetObserver(),让通知者Adapter获得ListView的观察者接口,这样就实现了双向沟通的通道,绑定完成。
我们再来看通知者BaseAdapter的源码
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();
}
/** * Notifies the attached observers that the underlying data is no longer valid * or available. Once invoked this adapter is no longer valid and should * not report further data set changes. */
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
public boolean areAllItemsEnabled() {
return true;
}
public boolean isEnabled(int position) {
return true;
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
public int getItemViewType(int position) {
return 0;
}
public int getViewTypeCount() {
return 1;
}
public boolean isEmpty() {
return getCount() == 0;
}
}
从上面的源码我们可以看到,BaseAdapter里面有一个Observerable通知者对象。在ListView调用了setAdapter()方法后,就实现了通知者与观察者的绑定,当Adapter里面的数据集合改变时,容器Activity通过调用Adapter.notifyDataSetChanged()然后再通过Observerable.notifyChanged方法通知ListView数据集改变了,然后就会调用ListView中DataObserver的onChaned()方法更新界面。
我们来看看真正的Observer和Observerable接口的源码。
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();
}
}
}
public class DataSetObservable extends Observable<DataSetObserver> {
/** * 通知观察者数据集改变了 */
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
由于Android框架系统比较复杂,因此它并没有采取Gof的实现接口的方式来实现观察者模式,而是通过委托的方式(嵌套一个通知者、观察者),委托通知者和观察者来实现通知和接收通知的任务。
观察者模式在Android中的应用还有很多。
比如:
广播机制中的BroadCast(通知者)和BroadReceiver(观察者);
Service中的Service(通知者)和ServiceConnection(观察者),当服务启动成功后,就调用onBind()方法通知ServiceConnection服务已经启动,通过 onServiceConnected()将Binder返回给观察者;