Android学习 ContentProvider数据更新与Observer模式
Android学习 ContentProvider数据更新与Observer模式
一 Observer模式
意图:
定义对象之间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被更新。
依赖(Dependents)、发布-订阅(Publish-Subscribe)。处理一对多情况下对象之间的依赖关系。
对象之间必然会存在依赖关系或者依赖关系会处于变动之中,如何解决依赖关系使他们之间的耦合性达到最小。
适用性:
l 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将二者封装在独立的对象以使他们各自独立的改变和复用;
l 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
l 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。
结构:
理解:
Subject维护对象的状态,当状态改变需要立即通知Observer更新状态与Subject保持状态的一致;
使对象状态维护者Subject并不需要去关心有哪些Observer关注或者依赖于所维护的对象,而专心负责维护对象;
同时如果某客户需要对某Subject所维护的对象感兴趣,可以通过对此Subject注册一个Observer来监听此对象的变化;
不需要监听的时候也可以注销掉监听;实现动态的关注对象状态的变化。
Subject维护的对象状态谁会去改变呢?书上提到是某Observer去改变,但也不一定如此;
Subject维护某一对象,对象的具体如何改变可以和Subject是没有关系,仅仅是知道对象状态改变了,
需要通知其他对象;对象状态的改变是有很多层次或者方式进行,不限于由Observer来改变。
更新由谁来触发呢?一是可以谁改变对象的状态谁来触发更新,这样各Observer状态的可以得到立即更新,
而且不需要客户端去负责更新,属于自动进行更新,但是每一次的对象状态变化都会执行更新,然而往往对象状态变化
是多个连续性的变化或者好几个变化间隔非常短,造成更新次数过多又非必要性的,降低效率;
二是由客户端负责更新,就可以控制何时进行更新最合适,避免整个状态变化中进行更新,而是整个连续性状态改变完成之后
一次性更新,但是此举将更新责任交给客户端,往往造成遗漏等不确定的缺陷。
对象状态变化怎么传递?一是在执行更新Update时,将对象以参数的形式传递给Observer一步到位——推模型,
对象的类型如何?(Subject\State\…),提供太多数据和细节可能造成某些缺陷,而且提供这些数据并不总是需要;
二是提供接口供Observer访问获取状态或者变化细节——拉模型,这样造成双向的通信形式,且不能确定提供什么样信息合适,
依赖性太强耦合性高;三是通过其它方式渠道,主动的去查询获取对象的状态;所以这三种方式都有其优缺点,
对象状态变化会有多种情况,如何传递状态变化的信息,可能需要具体问题具体分析解决。
对象变化了,会触发Subject的更新通知函数执行,完全不用关心谁关注此变化,有多少对象关注此变化;
而且都是通过抽象类实现,可以完全针对此接口进行编程,依赖于抽象而不是实现,降低Subject和Observer之间的耦合性。
所以Subject可以不知道有何Observer和多少Observer的存在,Observer需要知道Subject的存在。
二 Android中信息列表数据更新流程
在信息列表信息数据的变化需要及时反馈到界面上来,数据的存储是以SQLite数据库存储,
以ContentProvider形式访问;数据变化时是如何更新的呢?
看一下面这个图:
看到信息部分数据变化更新实现是在CursorAdapter中;
——>ContentObserver监听到数据变化消息之后;
——>通知CursorAdapter数据内容有变化;
——>通知信息相关的类进行数据更新重新进行查询;
ContentObserver从名称看得出来这是一个Observer模式的应用;
那么ContentObserver是如何实现监听有数据变化的呢?
ContentObserver在CursorAdapter中,肯定是CursorAdapter有关系,需要搞清楚ContentObserver与CursorAdapter之间的关系。
下面学习一下CursorAdapter中ContentObserver监听数据变化的流程;
三 Android中CursorAdapter的ContentObserver监听数据变化流程
要搞清楚ContentObserver与CursorAdapter之间的关系,以及CursorAdapter与AbstractCursor之间更深层次之间的关系,
才能弄清楚谁是Subject,如何注册的Observer,在数据变化时,Subject是如何通知到Observer的。
下面将采用倒推的方式一步一步的学习:
1 CursorAdapter中ContentObserver的注册到AbstractCursor过程
ContentObserver(抽象类)就是用来接收数据变化时的观察者,能进行异步派发派发接收到变化的通知。
public abstract class ContentObserver {
private Transport mTransport;
Handler mHandler;
public ContentObserver(Handler handler) {}
public IContentObserver getContentObserver() {}
//需要重写onChange
public void onChange(boolean selfChange) {}
public final void dispatchChange(boolean selfChange) {}
}
在CursorAdapter初始化时:
void init(Context context, Cursor c, boolean autoRequery) {
// ChangeObserver 继承 ContentObserver
mChangeObserver = new ChangeObserver();
//交给Cursor注册Observer
c.registerContentObserver(mChangeObserver);
}
Cursor中注册Observer过程:
Cursor是一个接口真正干活的是它实现者AbstractCursor
看下AbstractCursor 的registerContentObserver:
void registerContentObserver(ContentObserver observer) {
mContentObservable.registerObserver(observer);
}
ContentObservable又是什么呢?以及ContentObserver是怎么样一个类呢?
ContentObservable和前面ContentObserver不同:
ContentObservable类:
public class ContentObservable extends Observable<ContentObserver> {
public void registerObserver(ContentObserver observer) {}
public void dispatchChange(boolean selfChange) {}
public void notifyChange(boolean selfChange) {}
}
public abstract class Observable<T> {
protected final ArrayList<T> mObservers = new ArrayList<T>();
public void registerObserver(T observer) {}
public void unregisterObserver(T observer) {}
public void unregisterAll() {
}
所以ContentObservable就是专门用来注册ContentObserver,负责管理AbstractCursor作为Subject时接收注册Observer的,
而AbstractCursor此处就是Subject;
Observer——》ChangeObserver(CursorAdapter内部类)
Subject ——》AbstractCursor(成员ContentObservable负责管理Observer)
触发更新Update:
既然AbstractCursor作为此处的Subject,那么触发Observer更新是在何时进行呢?
AbstractCursor有这样一个接口:
protected void onChange(boolean selfChange) {
//触发所有的Observer
mContentObservable.dispatchChange(selfChange);
//这又是何缘故呢没搞懂 这里不会执行 下面再分析
if (mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
}
}
ContentObservable类中:
public void dispatchChange(boolean selfChange) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange);
}
}
}
ContentObserver类中:
public final void dispatchChange(boolean selfChange) {
if (mHandler == null) {
onChange(selfChange);
} else {
//异步的派发变化时通知
mHandler.post(new NotificationRunnable(selfChange));
}
}
这样就触发了所有注册到AbstarctCursor中ContentObserverable负责管理的所有ContentObserver;
此处便是CursorAdapter中的内部类ChangeObserver
下面看一下这个层次上的结构类图:
触发更新CursorAdapter中ChangeObserver中onChange函数执行;
这样就到了CursorAdapter更新流程上来了,这里属于Framework层;
从CursorAdapter然后就到了Application层,如前面所述的信息列表的更新流程。
这里的Observer模式中:
Subject——>AbstractCursor
Observer——>ChangeObserver(CursorAdapter内部类)
那么到此AbstractCursor是如何改变其中对象的状态和何时使其执行通知所有的观察者的呢?
作为Curosr虽然接口中提供了Update等操作来改变数据,但其实在AbstractCursor等并没有提供支持
来使用Update操作来改变数据,可以看到在4.0代码中已经将Update操作去掉;
Cursor仅仅是作为database query返回的结果用于获取其中的数据,所以AbstractCursor及其子类维护
其中的某个数据对象,可以自己实现对象状态的改变维护如MatrixCursor,也可以仅仅负责某个数据对象的维护,
数据对象状态真正改变不用去负责,仅需要在数据有变化时得到通知即可如SQLiteCursor;
所以还需要弄清楚Curosr作为Subject是维护的对象状态是如何变化且被通知到的。
下面看一下AbstractCursor作为Subject其中的对象状态改变是如何进行和被通知到的。
四 Android中AbstractCursor对象状态变化通知
更新通知启动:
从上面代码分析中可以知道AbstractCursor得到内容变化并通知其Observers是在下面函数中进行的:
protected void onChange(boolean selfChange) {
mContentObservable.dispatchChange(selfChange);
if (mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
}
}
顺着这条线找到onChange是何时被调用的:
找到位置是在AbstractCursor内部类SelfContentObserver中有如下:
protected static class SelfContentObserver extends ContentObserver {
WeakReference<AbstractCursor> mCursor;
public void onChange(boolean selfChange) {
AbstractCursor cursor = mCursor.get();
//这里调用其依赖类的上述的onChange类中
cursor.onChange(false); //这里传递的false
}
}
这又是一个ContentObserver观察者类,这又是怎么回事呢?Go On……
SelfContentObserver作为观察者:
找到SelfContentObserver使用方式:AbstractCursor中
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
mNotifyUri = notifyUri;
mContentResolver = cr;
mSelfObserver = new SelfContentObserver(this);
//进行Observer的注册
mContentResolver.registerContentObserver(
mNotifyUri, true, mSelfObserver);
}
SelfContentObserver作为了ContentResolver的一个Observer;
那函数setNotificationUri何时被调用呢?
答案是:ContentProvider中的Query()函数注释中有描述,派生类中需要调用这个c.setNotificationUri。
那么现在注册任务交给了ContentResolver了。
ContentService登场:
ContentResolver中注册Observer时
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer)
{
getContentService().registerContentObserver(uri, notifyForDescendents,
observer.getContentObserver());
}
看到注册Observer使用的是ContentService进行的,这是个系统服务SystemService;
ContentService又是干什么的勾当的呢?
从名称看到是内容服务,主要是数据库等提供解决方法的服务。因为数据库SQlite是一个C库,其中东东涉及很多需要。
ContentService中注册Observer函数:
public void registerContentObserver(Uri uri, boolean notifyForDescendents,
IContentObserver observer) {
mRootNode.addObserverLocked(uri, observer,
notifyForDescendents, mRootNode,
Binder.getCallingUid(), Binder.getCallingPid());
}
看到此函数有三个参数分别代表什么意义呢:
uri:针对对有变化的感兴趣进行监听的URI
notifyForDescendents:true表示以uri前缀开始的任何变化都进行通知;false表示完全匹配才进行通知;
observer:IContentObserver接口,提供了一个方法onChange,变化发生时Cursor需要更新时调用
使用此ContentService的registerContentObserver接口注册Observer,
通过指定Uri可以仅对数据库中感兴趣的数据有变化时,进行监听。具体实现细节可以看下ContentService源代码
中是如何构建一个树形结构来管理观察者对感兴趣数据的监听,看到根节点就是上述的mRootNode构建了一颗大树。
注册之后就是等待数据有变化时,进行监听了;此一布又是如何进行的呢?
触发数据更新通知:
对数据库中数据的更改操作都是通过ContentResolver 中使用ContentProvider进行修改的,数据变化就来源于此;
看看ContentProvider中数据修改函数Insert中都干了些什么。
ContentProvider是个abstract类,其中的数据更改操作的函数都是纯虚函数,但是看一下其中的Insert函数的注释:
As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver)
notifyChange()}after inserting.
在使用此函数插入数据之后,需要调用类ContentResolver中函数notifyChange,所以其子类中需要做这个事情;
可以看到在子类Insert函数中都执行了:
getContext().getContentResolver().notifyChange(newUri, null)
通过此到了ContentResolver的nofifyChange中,Go On……
ContentResolver中函数:
void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
getContentService().notifyChange(……);
}
进入到ContentService中的数据变化通知更新策略中;注册Observer是在ContentService中,
数据变化通知Observer更新数据也必然是要在ContentService中。下面看看这是如何执行的:
ContentService通知Observer更新:
ContentService函数中的notifyChange函数较为复杂,因为我们是注册对感兴趣的数据变化时才需要被通知到,
所以此处通过对树形结构存储的Observer,进行遍历查找到对变化感兴趣的Observer。
public void notifyChange(Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, boolean syncToNetwork)
{
//用于保存对此变化感兴趣的Observer
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
//收集对此变化感兴趣的Observer
mRootNode.collectObserversLocked(...,calls);
//发布数据变化通知到相应的Observer
final int numCalls = calls.size();
for (int i=0; i<numCalls; i++) {
ObserverCall oc = calls.get(i);
oc.mObserver.onChange(oc.mSelfNotify);
}
}
此处就走到了哪里呢?必然正是我们前面在AbstractCursor中所注册的SelfContentObserver的onChange函数中,
然后就到了AbstractCursor作为Subject时这一层的Observer模式的通知机制中。
这又是一个基于Observer模式的Subject——》Observer结构。
Subject:ContentService;
Observer:SelfContentObserver(AbstractCursor中内部类)
上面所述数据改变时从ConentService通知其关注这一变化的Observer;这一过程的类结构图大致如下:
五 Android中ContentService数据变化通知更新流程
从上面的整个代码流程可以看到这个过程中使用两个层次的Observer模式:
下面是注册Observer的时候的大致流程:
下面是数据变化时通知更新流程图:
整个过程大致如上所述,有两个层次的Observer模式的应用。从中我们可以看到Subject可以不同,
Observer相同,使Observer可以被复用,Subject不用去关心Observer,
Observer当然是要知道Subject存在的,Observer且能动态的添加删除。
具体ContentProvider更新过程可以参考这篇文章:
Android应用程序组件Content Provider的共享数据更新通知机制分析
地址:http://blog.csdn.net/Luoshengyang/article/details/6985171