定义
定义对象间一对多的关系,当一个对象改变时,所有和它关联的其他对象都得到该对象更新的消息,从而作出对应的处理。
简单的例子
Android内置了Observer和Observable,来看看观察者和被观察者的定义:
观察者
public interface Observer {
void update(Observable var1, Object var2);
}
被观察者
public class Observable {
//注册观察者
public synchronized void addObserver(Observer o) {}
public synchronized void deleteObserver(Observer o) {}
protected synchronized void setChanged() { }
//通知观察者去更新
public void notifyObservers() {}
...
}
来看看具体的例子:
//定义观察者
public class MyObserver implements Observer{
@Override
public void update(Observable o,Object b){
//接受到通知做相应的处理
}
}
//定义被观察者
public class MyObservable extends Observable{
public void postNews(String s){
//标志内容发生改变
setChanged();
//通知所有观察者
notifyObservers(s);
}
}
main(){
MObserver observer = new MObserver();
MObservable observable = new MObservable();
observable.addObserver(observer);
observable.postNews("发布消息了"); //此时所有的观察者都能收到这个信息
}
就是这么简单的一个例子,就实现了观察者模式,被观察者通知观察者的方式就是遍历内部的观察者列表,然后一个个的去调用其update()方法。
Android源码中的观察者模式
Android 源码中的ListView就用到了观察者模式,看一下具体的实现:
1.首先看自定义Adapter的实现:
private class MyAdapter extends BaseAdapter{
//实现四个方法
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
2.再看BaseAdapter的关键代码:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
//数据被观察者:这个类有两个方法,notifyChanged():当数据变化时,通知所有的观察者,当数据不可用时,通知观察者。
/**
* public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
*/
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);
}
//观察者就两个方法:
// onChanged(),onInvalidated()当数据源发生改变时调用。
//发送数据变化的通知,实际上就是DataSetObservable发送的通知
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
}
总结:BaseAdapter里面定义了一个被观察者,在里面注册和取消观察者,当数据变化时,会通知所有的Observer,【其实BaseAdapter就是一个被观察者】BaseAdapter来源于Adapter,看看Adapter的代码:
public interface Adapter{
//注册和取消观察者
void registerDataSetObserver(DataSetObserver var1);
void unregisterDataSetObserver(DataSetObserver var1);
// 自定义Adapter要实现的四个方法*/
int getCount();
Object getItem(int var1);
long getItemId(int var1);
View getView(int var1, View var2, ViewGroup var3);
}
再来看看调用流程:
final ListView mListView = new ListView(this);
/**实例化Adapter类,然后设置数据*/
MyAdapter myAdapter = new MyAdapter();
List<String> mlist = new ArrayList<>();
myAdapter.setmList(mlist);
//这步具体做了什么操作?
mListView.setAdapter(myAdapter);
//setAdapter()的源码:
public void setAdapter(ListAdapter adapter) {
//如果之前已经定义过了一个Adapter,那么注销所有的数据观察者
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
//从我们实现的getCount()方法中获取实际的数据数量
mItemCount = mAdapter.getCount();
checkFocus();
//创建观察者:关键地方,AdapterDataSetObserver继承自DataSetObserver,实现了onChanged()方法,并在其中执行更新布局的方法。
mDataSetObserver = new AdapterDataSetObserver();
//注册观察者,实际上就是调用了DataSetObservable的registerDataSetObserver(),将观察者和被观察者关联了起来
mAdapter.registerDataSetObserver(mDataSetObserver);
//....
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
//绘制UI
requestLayout();
}
//AdapterDataSetObserver的onChanged()方法
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();
}
//...
}
这个流程如下:
1.用户创建了ListView和自定义的Adapter,通过setAdaper()将listView和Adapter关联
2.Adapter内部创建了观察者和被观察者,并将观察者注册给被观察者(BaseAdapter即是被观察者)
3.当用户数据源发生改变时,必须调用adapter.notifyDataSetChanged方法,此时BaseAdapter内部的DataSetObservable会通知所有的观察者
4.当观察者收到了数据源发生改变时,执行OnChanged()方法,更新UI布局(requestLayout)(ListView里面封装了观察者)
综上:就是ListView所用到的完整的观察者模式的流程。
观察者模式除了ListView,还有BroadcastReceiver:
1、注册广播的方法:
registerReceiver(new BraodRE(),intentFilter);
2、实际上是执行ContextWapper的regist方法
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
3、mBase是ContextImpl的实例
register最终到达ContextImpl.registerReceiverInternal函数中,通过mPackageInfo.getReceiverDispatcher函数获得一个IIntentReceiver接口对象rd,这是一个Binder对象,接下来会把它传给ActivityManagerService,ActivityManagerService在收到相应的广播时,就会通过这个Binder对象来通知Activity来接受。
以下几个事件订阅框架就使用了观察者模式,对比下各自的优缺点如下:
1.EventBus :订阅函数可以异步执行,name pattern 模式,效率高。但使用不方便
2.Otto : 不能异步,使用注解,方便使用,效率比EventBus低
3.AndroidEventBus :可异步,订阅函数支持tag(类似于BroadcastReceiver的action),效率低于EventBus
还是根据实际情况来选择。