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

相關文章
相關標籤/搜索