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——》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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM