Android学习 ContentProvider数据更新与Observer模式

一 Observer模式

意图: android

  定义对象之间一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被更新。 数据库

  依赖(Dependents)、发布-订阅(Publish-Subscribe)。处理一对多状况下对象之间的依赖关系。 编程

对象之间必然会存在依赖关系或者依赖关系会处于变更之中,如何解决依赖关系使他们之间的耦合性达到最小。 异步

适用性: ide

  l  当一个抽象模型有两个方面,其中一个方面依赖于另外一个方面。将两者封装在独立的对象以使他们各自独立的改变和复用; 函数

  l  当一个对象的改变须要同时改变其余对象,而不知道具体有多少对象有待改变。 post

  l  当一个对象必须通知其余对象,而它又不能假定其余对象是谁。 学习

结构: this

  

      

理解: spa

  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——》ChangeObserverCursorAdapter内部类)

       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

相关文章
相关标签/搜索