午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

Android應(yīng)用程序組件Content Provider的共享數(shù)據(jù)更新通知機制分析

 lifei_szdz 2013-06-11

在Android系統(tǒng)中,應(yīng)用程序組件Content Provider為不同的應(yīng)用程序?qū)崿F(xiàn)數(shù)據(jù)共享提供了基礎(chǔ)設(shè)施,它主要通過Binder進程間通信機制和匿名共享內(nèi)存機制來實現(xiàn)的。關(guān)于數(shù)據(jù)共享的另一個話題便是數(shù)據(jù)更新通知機制了,即如果一個應(yīng)用程序?qū)蚕頂?shù)據(jù)做了修改,它應(yīng)該如何通知其它正在使用這些共享數(shù)據(jù)的應(yīng)用程序呢?本文將分析Content Provider的共享數(shù)據(jù)更新通知機制,為讀者解答這個問題。

        Android應(yīng)用程序組件Content Provider中的數(shù)據(jù)更新通知機制和Android系統(tǒng)中的廣播(Broadcast)通知機制的實現(xiàn)思路是相似的。在Android的廣播機制中,首先是接收者對自己感興趣的廣播進行注冊,接著當(dāng)發(fā)送者發(fā)出這些廣播時,接收者就會得到通知了。更多關(guān)于Android系統(tǒng)的廣播機制的知識,可以參考前面Android系統(tǒng)中的廣播(Broadcast)機制簡要介紹和學(xué)習(xí)計劃這一系列文章。然而,Content Provider中的數(shù)據(jù)監(jiān)控機制與Android系統(tǒng)中的廣播機制又有三個主要的區(qū)別,一是前者是通過URI來把通知的發(fā)送者和接收者關(guān)聯(lián)在一起的,而后者是通過Intent來關(guān)聯(lián)的,二是前者的通知注冊中心是由ContentService服務(wù)來扮演的,而后者是由ActivityManagerService服務(wù)來扮演的,三是前者負(fù)責(zé)接收數(shù)據(jù)更新通知的類必須要繼承ContentObserver類,而后者要繼承BroadcastReceiver類。之所以會有這些區(qū)別,是由于Content Proivder組件的數(shù)據(jù)共享功能本身就是建立在URI的基礎(chǔ)之上的,因此專門針對URI來設(shè)計另外一套通知機制會更實用和方便,而Android系統(tǒng)的廣播機制是一種更加通用的事件通知機制,它的適用范圍會更廣泛一些。

        與分析Android系統(tǒng)的廣播機制類似,我們把Content Provider的數(shù)據(jù)更新機制劃分為三個單元進行分析,第一個單元是ContentService的啟動過程,第二個單元是監(jiān)控數(shù)據(jù)變化的ContentObserver的注冊過程,第二個單元是數(shù)據(jù)更新通知的發(fā)送過程。

        與前面兩篇文章Android應(yīng)用程序組件Content Provider的啟動過程源代碼分析Android應(yīng)用程序組件Content Provider在應(yīng)用程序之間共享數(shù)據(jù)的原理分析一樣,本文仍然以Android應(yīng)用程序組件Content Provider應(yīng)用實例這篇文章介紹的應(yīng)用程序為例來分析Content Provider的數(shù)據(jù)更新機制。

        1. ContentService的啟動過程分析

        前面提到,在Content Provider的數(shù)據(jù)更新通知機制中,ContentService扮演者ContentObserver的注冊中心的角色,因此,它必須要系統(tǒng)啟動的時候就啟動起來,以便后面啟動起來的應(yīng)用程序可以使用它。在前面這篇文章Android系統(tǒng)進程Zygote啟動過程的源代碼分析中,我們提到,Android系統(tǒng)進程Zygote在啟動的時候,在啟動一個System進程來加載系統(tǒng)的一些關(guān)鍵服務(wù),而ContentService就這些關(guān)鍵服務(wù)之一了。在System進程中,負(fù)責(zé)加載系統(tǒng)關(guān)鍵服務(wù)的類為SystemServer類,它定義在frameworks/base/services/java/com/android/server/SystemServer.java文件中,它會通過啟動一個線程SystemThread來加載這些關(guān)鍵服務(wù):

  1. class ServerThread extends Thread {  
  2.     ......  
  3.   
  4.     @Override  
  5.     public void run() {  
  6.         ......  
  7.   
  8.         Looper.prepare();  
  9.   
  10.         // Critical services...  
  11.         try {  
  12.             ......  
  13.   
  14.             ContentService.main(context,  
  15.                 factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);  
  16.   
  17.             ......  
  18.   
  19.         }catch (RuntimeException e) {  
  20.             ......  
  21.         }  
  22.   
  23.         ......  
  24.   
  25.         Looper.loop();  
  26.         ......  
  27.     }  
  28. }  
        ContentService類定義在frameworks/base/core/java/android/content/ContentService.java文件中,它的main函數(shù)的實現(xiàn)如下所示:

  1. public final class ContentService extends IContentService.Stub {  
  2.     ......  
  3.   
  4.     public static IContentService main(Context context, boolean factoryTest) {  
  5.         ContentService service = new ContentService(context, factoryTest);  
  6.         ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);  
  7.         return service;  
  8.     }  
  9.   
  10.     ......  
  11. }  

        從這里我們就可以看到,在ContentService類的main函數(shù)中,會創(chuàng)建一個ContentService實例,然后把它添加到ServiceManager中去,這樣,ContentService服務(wù)就啟動起來了,  其它地方可以通過ServiceManager來獲得它的一個遠(yuǎn)程接口來使用它提供的服務(wù)。

        2. ContentObserver的注冊過程分析

        在前面這篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實例介紹的應(yīng)用程序Acticle中,主窗口MainActivity在創(chuàng)建的時候,會調(diào)用應(yīng)用程序上下文的ContentResolver接口來注冊一個自定義的ContentObserver來監(jiān)控ArticlesProvider這個Content Provider中的數(shù)據(jù)變化:

  1. public class MainActivity extends Activity implements View.OnClickListener, AdapterView.OnItemClickListener {  
  2.     ......  
  3.   
  4.     private ArticleAdapter adapter = null;  
  5.     private ArticleObserver observer = null;  
  6.   
  7.     ......  
  8.   
  9.     @Override  
  10.     public void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         ......  
  13.   
  14.         observer = new ArticleObserver(new Handler());  
  15.         getContentResolver().registerContentObserver(Articles.CONTENT_URI, true, observer);  
  16.   
  17.         ......  
  18.     }  
  19.   
  20.     private class ArticleObserver extends ContentObserver {  
  21.         public ArticleObserver(Handler handler) {  
  22.             super(handler);  
  23.         }  
  24.   
  25.         @Override  
  26.         public void onChange (boolean selfChange) {  
  27.             adapter.notifyDataSetChanged();  
  28.         }  
  29.     }  
  30.   
  31.     ......  
  32. }  
        從ContentObserver繼承下來的子類必須要實現(xiàn)onChange函數(shù)。當(dāng)這個ContentObserver子類負(fù)責(zé)監(jiān)控的數(shù)據(jù)發(fā)生變化時,ContentService就會調(diào)用它的onChange函數(shù)來處理,參數(shù)selfChange表示這個變化是否是由自己引起的,在我們這個情景中,不需要關(guān)注這個參數(shù)的值。在這個應(yīng)用程序中,ArticleObserver繼承了ContentObserver類,它負(fù)責(zé)監(jiān)控的URI是Articles.CONTENT_URI,它的值為"content://shy.luo.providers.articles/item",這個值是在這篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實例介紹的應(yīng)用程序ActiclesProvider中的Articles.java文件中定義的。當(dāng)所有以Articles.CONTENT_URI為前綴的URI對應(yīng)的數(shù)據(jù)發(fā)生改變時,ContentService都會調(diào)用這個ArticleObserver類的onChange函數(shù)來處理。在ArticleObserver類的onChange函數(shù)中,執(zhí)行的操作就是重新獲取ActiclesProvider中的數(shù)據(jù)來更新界面上的文章信息列表。

        在ArticleObserver類的構(gòu)造函數(shù)中,有一個參數(shù)handler,它的類型為Handler,它是從MainActivity類的onCreate函數(shù)中創(chuàng)建并傳過來的。通過前面這篇文章Android應(yīng)用程序消息處理機制(Looper、Handler)分析的學(xué)習(xí),我們知道,這個handler是用來分發(fā)和處理消息用的。由于MainActivity類的onCreate函數(shù)是在應(yīng)用程序的主線程中被調(diào)用的,因此,這個handler參數(shù)就是和應(yīng)用程序主線程的消息循環(huán)關(guān)聯(lián)在一起的。在后面我們分析數(shù)據(jù)更新通知的發(fā)送過程時,便會看到這個handler參數(shù)是如何使用的了。

        下面我們就開始分析注冊ArticleObserver來監(jiān)控ActiclesProvider中的數(shù)據(jù)變化的過程,首先來看一下這個過程的時序圖,然后再詳細(xì)分析每一個步驟:


        Step 1. ContentResolver.registerContentObserver

        這個函數(shù)定義在frameworks/base/core/java/android/content/ContentResolver.java文件中:

  1. public abstract class ContentResolver {  
  2.     ......  
  3.   
  4.     public final void registerContentObserver(Uri uri, boolean notifyForDescendents,  
  5.         ContentObserver observer)  
  6.     {  
  7.         try {  
  8.             getContentService().registerContentObserver(uri, notifyForDescendents,  
  9.                 observer.getContentObserver());  
  10.         } catch (RemoteException e) {  
  11.         }  
  12.     }  
  13.   
  14.     ......  
  15. }  
        當(dāng)參數(shù)notifyForDescendents為true時,表示要監(jiān)控所有以uri為前綴的URI對應(yīng)的數(shù)據(jù)變化。這個函數(shù)做了三件事情,一是調(diào)用getContentService函數(shù)來獲得前面已經(jīng)啟動起來了的ContentService遠(yuǎn)程接口,二是調(diào)用從參數(shù)傳進來的ContentObserver對象observer的getContentObserver函數(shù)來獲得一個Binder對象,三是通過調(diào)用這個ContentService遠(yuǎn)程接口的registerContentObserver函數(shù)來把這個Binder對象注冊到ContentService中去。

        Step 2.ContentResolver.getContentService

        這個函數(shù)定義在frameworks/base/core/java/android/content/ContentResolver.java文件中:

  1. public abstract class ContentResolver {  
  2.     ......  
  3.   
  4.     public static IContentService getContentService() {  
  5.         if (sContentService != null) {  
  6.             return sContentService;  
  7.         }  
  8.         IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);  
  9.         ......  
  10.         sContentService = IContentService.Stub.asInterface(b);  
  11.         ......  
  12.         return sContentService;  
  13.     }  
  14.   
  15.     private static IContentService sContentService;  
  16.     ......  
  17. }  
        在ContentResolver類中,有一個靜態(tài)成員變量sContentService,開始時它的值為null。當(dāng)ContentResolver類的getContentService函數(shù)第一次被調(diào)用時,它便會通過ServiceManager類的getService函數(shù)來獲得前面已經(jīng)啟動起來了的ContentService服務(wù)的遠(yuǎn)程接口,然后把它保存在sContentService變量中。這樣,當(dāng)下次ContentResolver類的getContentService函數(shù)再次被調(diào)用時,就可以直接把這個ContentService遠(yuǎn)程接口返回給調(diào)用者了。

        Step 3. ContentObserver.getContentObserver

        這個函數(shù)定義在frameworks/base/core/java/android/database/ContentObserver.java文件中:

  1. public abstract class ContentObserver {  
  2.     ......  
  3.   
  4.     private Transport mTransport;  
  5.   
  6.     ......  
  7.   
  8.     private static final class Transport extends IContentObserver.Stub {  
  9.         ContentObserver mContentObserver;  
  10.   
  11.         public Transport(ContentObserver contentObserver) {  
  12.             mContentObserver = contentObserver;  
  13.         }  
  14.   
  15.         ......  
  16.     }  
  17.   
  18.     ......  
  19.   
  20.     public IContentObserver getContentObserver() {  
  21.         synchronized(lock) {  
  22.             if (mTransport == null) {  
  23.                 mTransport = new Transport(this);  
  24.             }  
  25.             return mTransport;  
  26.         }  
  27.     }  
  28.   
  29.     ......  
  30. }  
        ContentObserver類的getContentObserver函數(shù)返回的是一個成員變量mTransport,它的類型為ContentObserver的內(nèi)部類Transport。從Transport類的定義我們可以知道,它有一個成員變量mContentObserver,用來保存與對應(yīng)的ContentObserver對象。同時我們還可以看出,ContentObserver類的成員變量mTransport是一個Binder對象,它是要傳遞給ContentService服務(wù)的,以便當(dāng)ContentObserver所監(jiān)控的數(shù)據(jù)發(fā)生變化時,ContentService服務(wù)可以通過這個Binder對象通知相應(yīng)的ContentObserver它監(jiān)控的數(shù)據(jù)發(fā)生變化了。

        Step 4. ContentService.registerContentObserver

        這個函數(shù)定義在frameworks/base/core/java/android/content/ContentService.java文件中:

  1. public final class ContentService extends IContentService.Stub {  
  2.     ......  
  3.   
  4.     private final ObserverNode mRootNode = new ObserverNode("");  
  5.   
  6.     ......  
  7.   
  8.     public void registerContentObserver(Uri uri, boolean notifyForDescendents,  
  9.             IContentObserver observer) {  
  10.         ......  
  11.   
  12.         synchronized (mRootNode) {  
  13.             mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode);  
  14.             ......  
  15.         }  
  16.     }  
  17.   
  18.     ......  
  19. }  
        它調(diào)用了ContentService類的成員變量mRootNode的addObserverLocked函數(shù)來注冊這個ContentObserver對象observer。成員變量mRootNode的類型為ContentService在內(nèi)部定義的一個類ObserverNode。

        Step 5. ObserverNode.addObserverLocked

        這個函數(shù)定義在frameworks/base/core/java/android/content/ContentService.java文件中:

  1. public final class ContentService extends IContentService.Stub {  
  2.     ......  
  3.   
  4.     public static final class ObserverNode {  
  5.         ......  
  6.   
  7.         private String mName;  
  8.         private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();  
  9.         private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();  
  10.   
  11.         public ObserverNode(String name) {  
  12.             mName = name;  
  13.         }  
  14.   
  15.         private String getUriSegment(Uri uri, int index) {  
  16.             if (uri != null) {  
  17.                 if (index == 0) {  
  18.                     return uri.getAuthority();  
  19.                 } else {  
  20.                     return uri.getPathSegments().get(index - 1);  
  21.                 }  
  22.             } else {  
  23.                 return null;  
  24.             }  
  25.         }  
  26.   
  27.         private int countUriSegments(Uri uri) {  
  28.             if (uri == null) {  
  29.                 return 0;  
  30.             }  
  31.             return uri.getPathSegments().size() + 1;  
  32.         }  
  33.   
  34.         public void addObserverLocked(Uri uri, IContentObserver observer,  
  35.                 boolean notifyForDescendents, Object observersLock) {  
  36.             addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock);  
  37.         }  
  38.   
  39.         private void addObserverLocked(Uri uri, int index, IContentObserver observer,  
  40.                 boolean notifyForDescendents, Object observersLock) {  
  41.             // If this is the leaf node add the observer  
  42.             if (index == countUriSegments(uri)) {  
  43.                 mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock));  
  44.                 return;  
  45.             }  
  46.   
  47.             // Look to see if the proper child already exists  
  48.             String segment = getUriSegment(uri, index);  
  49.             if (segment == null) {  
  50.                 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");  
  51.             }  
  52.             int N = mChildren.size();  
  53.             for (int i = 0; i < N; i++) {  
  54.                 ObserverNode node = mChildren.get(i);  
  55.                 if (node.mName.equals(segment)) {  
  56.                     node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);  
  57.                     return;  
  58.                 }  
  59.             }  
  60.   
  61.             // No child found, create one  
  62.             ObserverNode node = new ObserverNode(segment);  
  63.             mChildren.add(node);  
  64.             node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);  
  65.         }  
  66.   
  67.         ......  
  68.     }  
  69.   
  70.     ......  
  71. }  
        從這里我們就可以看出,注冊到ContentService中的ContentObserver按照樹形來組織,樹的節(jié)點類型為ObserverNode,而樹的根節(jié)點就為ContentService類的成員變量mRootNode。每一個ObserverNode節(jié)點都對應(yīng)一個名字,它是從URI中解析出來的。

        在我們這個情景中,傳進來的uri為"content://shy.luo.providers.articles/item",從Step 3調(diào)用mRootNode的addObserverLocked函數(shù)來往樹上增加一個ObserverNode節(jié)點時,傳進來的參數(shù)index的值為0,而調(diào)用countUriSegments("content://shy.luo.providers.articles/item")函數(shù)的返回值為2,不等于index的值,因此就會往下執(zhí)行,而通過調(diào)用getUriSegment("content://shy.luo.providers.articles/item", 0)函數(shù)得到的返回值為"shy.luo.providers.articles"。假設(shè)這里是第一次調(diào)用樹的根節(jié)點mRootNode來增加"content://shy.luo.providers.articles/item"這個URI,那么在接下來的for循環(huán)中,就不會在mRootNode的孩子節(jié)點列表mChildren中找到與名稱"shy.luo.providers.articles"對應(yīng)的ObserverNode,于是就會以"shy.luo.providers.articles"為名稱來創(chuàng)建一個新的ObserverNode,并增加到mRootNode的孩子節(jié)點列表mChildren中去,并以這個新的ObserverNode來開始新一輪的addObserverLocked函數(shù)調(diào)用。

        第二次進入到addObserverLocked函數(shù)時,countUriSegments("content://shy.luo.providers.articles/item")的值仍為2,而index的值為1,因此就會往下執(zhí)行,這時候通過調(diào)用getUriSegment("content://shy.luo.providers.articles/item", 1)函數(shù)得到的返回值為"item"。假設(shè)這時候在以"shy.luo.providers.articles/item"為名稱的ObserverNode中不存在名稱為"item"的孩子節(jié)點,于是又會以"item"為名稱來創(chuàng)建一個新的ObserverNode,并以這個新的ObserverNode來開始新一輪的addObserverLocked函數(shù)調(diào)用。

        第三次進入到addObserverLocked函數(shù)時,countUriSegments("content://shy.luo.providers.articles/item")的值仍為2,而index的值也為2,因此就會新建一個ObserverEntry對象,并保存在這個以"item"為名稱的ObserverNode的ContentObserver列表mObervers中。

        最終我們得到的樹形結(jié)構(gòu)如下所示:

        mRootNode("")

            -- ObserverNode("shy.luo.providers.articles")

                --ObserverNode("item") , which has a ContentObserver in mObservers  
       這樣,ContentObserver的注冊過程就完成了。

       3. 數(shù)據(jù)更新通知的發(fā)送過程

       在前面這篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實例介紹的應(yīng)用程序Acticle中,當(dāng)調(diào)用ArticlesAdapter類的insertArticle往ArticlesProvider中增加一個文章信息條目時:

  1. public class ArticlesAdapter {  
  2.     ......  
  3.   
  4.     public long insertArticle(Article article) {  
  5.         ContentValues values = new ContentValues();  
  6.         values.put(Articles.TITLE, article.getTitle());  
  7.         values.put(Articles.ABSTRACT, article.getAbstract());  
  8.         values.put(Articles.URL, article.getUrl());  
  9.   
  10.         Uri uri = resolver.insert(Articles.CONTENT_URI, values);  
  11.         String itemId = uri.getPathSegments().get(1);  
  12.   
  13.         return Integer.valueOf(itemId).longValue();  
  14.     }  
  15.   
  16.     ......  
  17. }  
        便會進入到應(yīng)用程序ArticlesProvider中的ArticlesProvider類的insert函數(shù)中:

  1. public class ArticlesProvider extends ContentProvider {  
  2.     ......  
  3.   
  4.     @Override  
  5.     public Uri insert(Uri uri, ContentValues values) {  
  6.         if(uriMatcher.match(uri) != Articles.ITEM) {  
  7.             throw new IllegalArgumentException("Error Uri: " + uri);  
  8.         }  
  9.   
  10.         SQLiteDatabase db = dbHelper.getWritableDatabase();  
  11.   
  12.         long id = db.insert(DB_TABLE, Articles.ID, values);  
  13.         if(id < 0) {  
  14.             throw new SQLiteException("Unable to insert " + values + " for " + uri);  
  15.         }  
  16.   
  17.         Uri newUri = ContentUris.withAppendedId(uri, id);  
  18.         resolver.notifyChange(newUri, null);  
  19.   
  20.         return newUri;  
  21.     }  
  22.   
  23.     ......  
  24. }  
        從上面?zhèn)鱽淼膮?shù)uri的值為"content://shy.luo.providers.articles/item"。假設(shè)當(dāng)這個函數(shù)把數(shù)據(jù)成功增加到SQLite數(shù)據(jù)庫之后,返回來的id值為n,于是通過調(diào)用ContentUris.withAppendedId("content://shy.luo.providers.articles/item", n)得到的newUri的值就為"content://shy.luo.providers.articles/item/n"。這時候就會調(diào)用下面語句來通知那些注冊了監(jiān)控"content://shy.luo.providers.articles/item/n"這個URI的ContentObserver,它監(jiān)控的數(shù)據(jù)發(fā)生變化了:

  1. resolver.notifyChange(newUri, null);  
        下面我們就開始分析這個數(shù)據(jù)變化通知的發(fā)送過程,首先來看一下這個過程的時序圖,然后再詳細(xì)分析每一個步驟:


        Step 1. ContentResolver.notifyChange
        這個函數(shù)定義在frameworks/base/core/java/android/content/ContentResolver.java文件中:

  1. public abstract class ContentResolver {  
  2.     ......  
  3.   
  4.     public void notifyChange(Uri uri, ContentObserver observer) {  
  5.         notifyChange(uri, observer, true /* sync to network */);  
  6.     }  
  7.   
  8.     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {  
  9.         try {  
  10.             getContentService().notifyChange(  
  11.                 uri, observer == null ? null : observer.getContentObserver(),  
  12.                 observer != null && observer.deliverSelfNotifications(), syncToNetwork);  
  13.         } catch (RemoteException e) {  
  14.         }  
  15.     }  
  16.   
  17.     ......  
  18. }  
        這里調(diào)用了ContentService的遠(yuǎn)接程口來調(diào)用它的notifyChange函數(shù)來發(fā)送數(shù)據(jù)更新通知。

        Step 2. ContentService.notifyChange

        這個函數(shù)定義在frameworks/base/core/java/android/content/ContentService.java文件中:

  1. public final class ContentService extends IContentService.Stub {  
  2.     ......  
  3.   
  4.     public void notifyChange(Uri uri, IContentObserver observer,  
  5.             boolean observerWantsSelfNotifications, boolean syncToNetwork) {  
  6.         ......  
  7.   
  8.         try {  
  9.             ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();  
  10.             synchronized (mRootNode) {  
  11.                 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,  
  12.                     calls);  
  13.             }  
  14.             final int numCalls = calls.size();  
  15.             for (int i=0; i<numCalls; i++) {  
  16.                 ObserverCall oc = calls.get(i);  
  17.                 try {  
  18.                     oc.mObserver.onChange(oc.mSelfNotify);  
  19.                     ......  
  20.                 } catch (RemoteException ex) {  
  21.                     ......  
  22.                 }  
  23.             }  
  24.             ......  
  25.         } finally {  
  26.             ......  
  27.         }  
  28.     }  
  29.   
  30.     ......  
  31. }  
        這個函數(shù)主要做了兩件事情,第一件事情是調(diào)用ContentService的成員變量mRootNode的collectObserverLocked函數(shù)來收集那些注冊了監(jiān)控"content://shy.luo.providers.articles/item/n"這個URI的ContentObserver,第二件事情是分別調(diào)用了這些ContentObserver的onChange函數(shù)來通知它們監(jiān)控的數(shù)據(jù)發(fā)生變化了。

        Step 3. ObserverNode.collectObserversLocked

        這個函數(shù)定義在frameworks/base/core/java/android/content/ContentService.java文件中:

  1. public final class ContentService extends IContentService.Stub {  
  2.     ......  
  3.   
  4.     public static final class ObserverNode {  
  5.         ......  
  6.   
  7.         private void collectMyObserversLocked(boolean leaf, IContentObserver observer,  
  8.                 boolean selfNotify, ArrayList<ObserverCall> calls) {  
  9.             int N = mObservers.size();  
  10.             IBinder observerBinder = observer == null ? null : observer.asBinder();  
  11.             for (int i = 0; i < N; i++) {  
  12.                 ObserverEntry entry = mObservers.get(i);  
  13.   
  14.                 // Don't notify the observer if it sent the notification and isn't interesed  
  15.                 // in self notifications  
  16.                 if (entry.observer.asBinder() == observerBinder && !selfNotify) {  
  17.                     continue;  
  18.                 }  
  19.   
  20.                 // Make sure the observer is interested in the notification  
  21.                 if (leaf || (!leaf && entry.notifyForDescendents)) {  
  22.                     calls.add(new ObserverCall(this, entry.observer, selfNotify));  
  23.                 }  
  24.             }  
  25.         }  
  26.   
  27.         public void collectObserversLocked(Uri uri, int index, IContentObserver observer,  
  28.                 boolean selfNotify, ArrayList<ObserverCall> calls) {  
  29.             String segment = null;  
  30.             int segmentCount = countUriSegments(uri);  
  31.             if (index >= segmentCount) {  
  32.                 // This is the leaf node, notify all observers  
  33.                 collectMyObserversLocked(true, observer, selfNotify, calls);  
  34.             } else if (index < segmentCount){  
  35.                 segment = getUriSegment(uri, index);  
  36.                 // Notify any observers at this level who are interested in descendents  
  37.                 collectMyObserversLocked(false, observer, selfNotify, calls);  
  38.             }  
  39.   
  40.             int N = mChildren.size();  
  41.             for (int i = 0; i < N; i++) {  
  42.                 ObserverNode node = mChildren.get(i);  
  43.                 if (segment == null || node.mName.equals(segment)) {  
  44.                     // We found the child,  
  45.                     node.collectObserversLocked(uri, index + 1, observer, selfNotify, calls);  
  46.                     if (segment != null) {  
  47.                         break;  
  48.                     }  
  49.                 }  
  50.             }  
  51.         }  
  52.     }  
  53. }  
        第一次調(diào)用collectObserversLocked時,是在mRootNode的這個ObserverNode節(jié)點中進行收集ContentObserver的。這時候傳進來的uri的值為"content://shy.luo.providers.articles/item/n",index的值為0。調(diào)用countUriSegments("content://shy.luo.providers.articles/item/n")函數(shù)得到的返回值為3,于是就會調(diào)用下面語句:

  1. segment = getUriSegment("content://shy.luo.providers.articles/item/n",0);  
  2. // Notify any observers at this level who are interested in descendents  
  3. collectMyObserversLocked(false, observer, selfNotify, calls);  
        這里得到的segment為"shy.luo.providers.articles"。在我們這個情景中,假設(shè)mRootNode這個節(jié)點中沒有注冊ContentObserver,于是調(diào)用collectMyObserversLocked函數(shù)就不會收集到ContentObserver。

        在接下來的for循環(huán)中,在mRootNode的孩子節(jié)點列表mChildren中查找名稱等于"shy.luo.providers.articles"的OberverNode節(jié)點。在上面分析ContentObserver的注冊過程時,我們已經(jīng)往mRootNode的孩子節(jié)點列表mChildren中增加了一個名稱為"shy.luo.providers.articles"的OberverNode節(jié)點,因此,這里會成功找到它,并且調(diào)用它的collectObserversLocked函數(shù)來繼續(xù)收集ContentObserver。

        第二次進入到collectObserversLocked函數(shù)時,是在名稱為"shy.luo.providers.articles"的OberverNode節(jié)點中收集ContentObserver的。這時候傳來的uri值不變,但是index的值為1,于是執(zhí)行下面語句:

  1. segment = getUriSegment("content://shy.luo.providers.articles/item/n",1);  
  2. // Notify any observers at this level who are interested in descendents  
  3. collectMyObserversLocked(false, observer, selfNotify, calls);  
        這里得到的segment為"item"。在我們這個情景中,我們沒有在名稱為"shy.luo.providers.articles"的OberverNode節(jié)點中注冊有ContentObserver,因此這里調(diào)用collectMyObserversLocked函數(shù)也不會收集到ContentObserver。

        在接下來的for循環(huán)中,在名稱為"shy.luo.providers.articles"的ObserverNode節(jié)點的孩子節(jié)點列表mChildren中查找名稱等于"item"的OberverNode節(jié)點。在上面分析ContentObserver的注冊過程時,我們已經(jīng)往名稱為"shy.luo.providers.articles"的ObserverNode節(jié)點的孩子節(jié)點列表mChildren中增加了一個名稱為"item"的OberverNode節(jié)點,因此,這里會成功找到它,并且調(diào)用它的collectObserversLocked函數(shù)來繼續(xù)收集ContentObserver。

        第三次進入到collectObserversLocked函數(shù)時,是在名稱為"shy.luo.providers.articles"的OberverNode節(jié)點的子節(jié)點中名稱為"item"的ObserverNode節(jié)點中收集ContentObserver的。這時候傳來的uri值不變,但是index的值為2,于是執(zhí)行下面語句:

  1. segment = getUriSegment("content://shy.luo.providers.articles/item/n",2);  
  2. // Notify any observers at this level who are interested in descendents  
  3. collectMyObserversLocked(false, observer, selfNotify, calls);  
        這里得到的segment為"n"。前面我們已經(jīng)在名稱為"shy.luo.providers.articles"的OberverNode節(jié)點的子節(jié)點中名稱為"item"的ObserverNode節(jié)點中注冊了一個ContentObserver,即ArticlesObserver,因此這里調(diào)用collectMyObserversLocked函數(shù)會收集到這個ContentObserver。注意,這次調(diào)用collectMyObserversLocked函數(shù)時,雖然傳進去的參數(shù)leaf為false,但是由于我們注冊ArticlesObserver時,指定了notifyForDescendents參數(shù)為true,因此,這里可以把它收集回來。

        在接下來的for循環(huán)中,繼續(xù)在該節(jié)點的子節(jié)點列表mChildren中查找名稱等于"n"的OberverNode節(jié)點。在我們這個情景中,不存在這個名稱為"n"的子節(jié)點了,于是收集ContentObserver的工作就結(jié)束了,收集結(jié)果是只有一個ContentObserver,即我們在前面注冊的ArticlesObserver。

        返回到Step 2中,調(diào)用下面語句來通知相應(yīng)的ContentObserver,它們監(jiān)控的數(shù)據(jù)發(fā)生變化了:

  1. for (int i=0; i<numCalls; i++) {  
  2.     ObserverCall oc = calls.get(i);  
  3.     try {  
  4.         oc.mObserver.onChange(oc.mSelfNotify);  
  5.         ......  
  6.     } catch (RemoteException ex) {  
  7.         ......  
  8.     }  
  9. }  
        前面我們在分析ContentObserver的注冊過程的Step 3時,介紹到注冊到ContentService服務(wù)中的ContentObserver是一個在ContentObserver內(nèi)部定義的一個類Transport的對象的遠(yuǎn)程接口,于是這里調(diào)用這個接口的onChange函數(shù)時,就會進入到ContentObserver的內(nèi)部類Transport的onChange函數(shù)中去。

        Step 4. Transport.onChange

        這個函數(shù)定義在frameworks/base/core/java/android/database/ContentObserver.java文件中:

  1. public abstract class ContentObserver {  
  2.     ......  
  3.   
  4.     private static final class Transport extends IContentObserver.Stub {  
  5.         ContentObserver mContentObserver;  
  6.       
  7.         ......  
  8.   
  9.         public void onChange(boolean selfChange) {  
  10.             ContentObserver contentObserver = mContentObserver;  
  11.             if (contentObserver != null) {  
  12.                 contentObserver.dispatchChange(selfChange);  
  13.             }  
  14.         }  
  15.   
  16.         ......  
  17.     }  
  18.   
  19.     ......  
  20. }  
        前面我們在分析ContentObserver的注冊過程的Step 3時,把ArticlesObserver這個ContentObserver保存在了這個Transport對象的mContentObserver成員變量中,因此,會調(diào)用它的dispatchChange函數(shù)來執(zhí)行數(shù)據(jù)更新通知的操作。

        Step 5. ContentObserver.dispatchChange

        這個函數(shù)定義在frameworks/base/core/java/android/database/ContentObserver.java文件中:

  1. public abstract class ContentObserver {  
  2.     ......  
  3.   
  4.     public final void dispatchChange(boolean selfChange) {  
  5.         if (mHandler == null) {  
  6.             onChange(selfChange);  
  7.         } else {  
  8.             mHandler.post(new NotificationRunnable(selfChange));  
  9.         }  
  10.     }  
  11. }  
        在前面分析ArticlesObserver的注冊過程時,我們以應(yīng)用程序Article的主線程的消息循環(huán)創(chuàng)建了一個Handler,并且以這個Handler來創(chuàng)建了這個ArticlesObserver,這個Handler就保存在ArticlesObserver的父類ContentObserver的成員變量mHandler中。因此,這里的mHandler不為null,于是把這個數(shù)據(jù)更新通知封裝成了一個消息,放到應(yīng)用程序Article的主線程中去處理,最終這個消息是由NotificationRunnable類的run函數(shù)來處理的。

        Step 6. NotificationRunnable.run

        這個函數(shù)定義在frameworks/base/core/java/android/database/ContentObserver.java文件中:

  1. public abstract class ContentObserver {  
  2.     ......  
  3.   
  4.     private final class NotificationRunnable implements Runnable {  
  5.         private boolean mSelf;  
  6.   
  7.         public NotificationRunnable(boolean self) {  
  8.             mSelf = self;  
  9.         }  
  10.   
  11.         public void run() {  
  12.             ContentObserver.this.onChange(mSelf);  
  13.         }  
  14.     }  
  15.   
  16.     ......  
  17. }  
        這個函數(shù)就直接調(diào)用ContentObserver的子類的onChange函數(shù)來處理這個數(shù)據(jù)更新通知了。在我們這個情景中,這個ContentObserver子類便是ArticlesObserver了。

        Step 7. ArticlesObserver.onChange

        這個函數(shù)定義在前面一篇文章Android應(yīng)用程序組件Content Provider應(yīng)用實例介紹的應(yīng)用程序Artilce源代碼工程目錄下,在文件為packages/experimental/Article/src/shy/luo/article/MainActivity.java中:

  1. public class MainActivity extends Activity implements View.OnClickListener, AdapterView.OnItemClickListener {  
  2.     ......  
  3.   
  4.     private class ArticleObserver extends ContentObserver {  
  5.         ......  
  6.   
  7.         @Override  
  8.         public void onChange (boolean selfChange) {  
  9.             adapter.notifyDataSetChanged();  
  10.         }  
  11.     }  
  12.   
  13.     ......  
  14. }  
       這里它要執(zhí)行的操作便是更新界面上的ListView列表中的文章信息了,以便反映ArticlesProvider中的最新數(shù)據(jù)。

     這樣,Android應(yīng)用程序組件Content Provider的共享數(shù)據(jù)更新通知機制就分析完了,整個Android應(yīng)用程序組件Content Provider的學(xué)習(xí)也結(jié)束了,重新學(xué)習(xí)請回到Android應(yīng)用程序組件Content Provider簡要介紹和學(xué)習(xí)計劃一文。

老羅的新浪微博:http://weibo.com/shengyangluo,歡迎關(guān)注!

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多