在分析android源码前,先来了解观察者模式的定义与使用。
一.简介
1.定义:对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
2.角色:观察者(Observer),被观察者(Observable)
观察者:(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
被观察者:被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。
3.根据对它们各自的定义,观察者/被观察者需要具备以下几个特性:
被观察者:
(1).需要一个容器来保存所以的观察者,如下定义的ArrayList集合类。
(2).需要一个注册到容器的方法,及从容器的释放的方法,如registerObserver和unregisterObserver。
(3).当被观察者自身改变时,需要一个方法来通知所有的观察者,如notifyChanged
Public class Observable< Observer >{ ArrayList< Observer > mObservers = new ArrayList< Observer >(); public void registerObserver(Observer observer){} public void unregisterObserver(Observer observer) {} public void notifyChanged() {…. onChanged ()……} }观察者:
提供一个接口,当被观察者自身改变时,观察者需要做出什么动作。
Public class Observer{ public void onChanged(){} }
以上是对于观察者于被观察者的定义。那么这种模式是怎么使用的呢?一般我们实现好观察者Observer后,需要用registerObserver把Observer注册到Observable中,这个Observer最后是保存在了Observable的集合中,当某个地方需要通知Observer改变时,就调用notifyChanged方法,这个方法会循环Observable的集合,并调用集合中的Observer对象的onChanged方法,达到了通知的目的。
二.源代码分析:
源代码中很多地方都使用了观察者模式,其中最为常见的有以下几种:
被观察者:DataSetObservable,ContentObservable,Observable,ContentService
观察者: DataSetObserver, ContentObserver,
其中,DataSetObservable与ContentObservable都是继承自Observable,它们对应的观察者是DataSetObserver与ContentObserver。ContentService从特性上来看,也属于被观察者之列,它对应的观察者是ContentObserver。ContentService的实现比较复杂,这个后面会说到。
围绕上面的几种被观察者-观察者模式,催生了Android中的数据消息通知机制,主要涉及的几个使用类如下:
BaseAdapter,AbstractCursor,CursorAdapter
现在,让我们先从基础类来看一下,然后再接下去分析以上的几个类。
(一).基础类Observable:
public abstract class Observable<T> { protected final ArrayList<T> mObservers = new ArrayList<T>(); public void registerObserver(T observer) { if (observer == null) { throw new IllegalArgumentException("The observer is null."); } synchronized(mObservers) { if (mObservers.contains(observer)) { throw new IllegalStateException("Observer " + observer + " is already registered."); } mObservers.add(observer); } } public void unregisterObserver(T observer) { if (observer == null) { throw new IllegalArgumentException("The observer is null."); } synchronized(mObservers) { int index = mObservers.indexOf(observer); if (index == -1) { throw new IllegalStateException("Observer " + observer + " was not registered."); } mObservers.remove(index); } } public void unregisterAll() { synchronized(mObservers) { mObservers.clear(); } } }
被观察者:
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(); } } } }
public abstract class DataSetObserver { public void onChanged() { // Do nothing } public void onInvalidated() { // Do nothing } } private class MyDataSetObserver extends DataSetObserver { @Override public void onChanged() { mDataValid = true; notifyDataSetChanged(); } @Override public void onInvalidated() { mDataValid = false; notifyDataSetInvalidated(); } } }
上图的流程可以分为两条:
1. 注册过程:在适配的时候把观察者AdapterDataSetObserver注册到DataSetObservable中,并调用requestLayout方法,最终会调用到view中的requestLayout方法,这个方法的作用就是重新绘制UI。BaseAdapter的部分代码如下:
private final DataSetObservable mDataSetObservable = new DataSetObservable(); public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); }
(三).ContentObservable与ContentObserver
要讲这个模式之前,我们先来看一个ListView加载数据的例子,如下图:
上图是我们进入短信列表的时候,从数据库中加载的数据并显示的过程。如果对于LoaderManager加载数据不熟悉的同学,可以先去预习一下。从步骤5开始,ConversationList已经拿到了需要加载的Cursor类型的数据。接下来它会执行CursorAdapter的swapCursor()方法,并注册两个观察者。注册结束后,会调用notifyDataSetChanged()进行页面更新,这样我们所见到的短信列表就显示出来了。上面我们已经讲过,ConversationList会在OnCreate()方法中设置适配器setListAdapter(),在OnStart()方法中加载数据并更新UI。
接下来了解一下以下两个类:AbstractCursor,CursorAdapter
我们看看它们的继承关系:
其中AbstractCursor的部分代码如下:
private final DataSetObservable mDataSetObservable = new DataSetObservable(); private final ContentObservable mContentObservable = new ContentObservable(); public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void registerContentObserver(ContentObserver observer) { mContentObservable.registerObserver(observer); } public void setNotificationUri(ContentResolver cr, Uri notifyUri, int userHandle) { synchronized (mSelfObserverLock) { mNotifyUri = notifyUri; mContentResolver = cr; if (mSelfObserver != null) { mContentResolver.unregisterContentObserver(mSelfObserver); } mSelfObserver = new SelfContentObserver(this); mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver, userHandle); mSelfObserverRegistered = true; } }
public Cursor swapCursor(Cursor newCursor) { if (newCursor == mCursor) { return null; } Cursor oldCursor = mCursor; if (oldCursor != null) { if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver); if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver); } mCursor = newCursor; if (newCursor != null) { if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver); if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver); mRowIDColumn = newCursor.getColumnIndexOrThrow("_id"); mDataValid = true; // notify the observers about the new cursor notifyDataSetChanged(); } else { mRowIDColumn = -1; mDataValid = false; // notify the observers about the lack of a data set notifyDataSetInvalidated(); } return oldCursor; }
在这个方法中,它调用了AbstractCursor的registerContentObserver和registerDataSetObserver方法,并调用了父类的notifyDataSetChanged方法,是不是很熟悉,这个最终会走到View更新UI的过程。好了,铺垫得差不多了,也该放张图了:
上图可以分为两部分来看:
注册过程:可以看到有三种注册方法,其中两种是注册到ContentService中,一种是注册到ContentObservable中。如果使用setNotificationUri进行注册,那么我们不用自己实现观察者类,它使用的将是SelfContentObserver。看看它需要传入的参数:
public void setNotificationUri(ContentResolver cr, Uri notifyUri)。
ContentResolver对象我们可以很方便的得到,需要在意的是Uri而已,这意味着我们如果需要监听某个uri,只需要传入正确的uri,并适配好,当数据改变时,UI就会自动更新。上图中的13对应的是7,意味着需要自己实现观察者类,并实现其onChange的逻辑即可。至于1中的registerContentObserver方法,它的使用是在CursorAdapter中。
通知过程:从6开始,当插入数据时,其会调用ContentService通知SelfContentObserver执行onChange()方法。而这个onChange()方法也调用dispatchChange()对ContentObservable中的ChangeObserver进行通知,接下来就是普通的调用,直到调用notifyChanged()方法对DataSetObservable的MyDataSetObserver进行通知,最后就是更新UI的过程。可以看到,在这过程中,使用了三次被观察者-观察者的消息通知机制,也是比较混乱的,想要缕清其中的关系,就得抓住:什么时候注册,注册的是谁,什么时候通知,通知的是谁?那么,为什么使用了这么多的观察者模式?
补充:
ContentService的实现也是相当复杂的。主要复杂在于它管理观察者的方式上,ContentService使用了树形结构来保存注册上来的观察者,其节点类为ObserverNode,而且它的使用一般是通过ContentResolver来实现。有时间的话可以去研究研究。