国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android System Server大綱之ContentService和ContentProvider原理剖析

2019-11-06 09:44:17
字體:
來源:轉載
供稿:網友

Android System Server大綱之ContentService和ContentPRovider原理剖析

內容提供程序

觀察內容提供商

Android System Server大綱之ContentService和ContentProvider原理剖析前言APP發起查詢深入ContentResolver準備工作獲取ContentProvider公布ContentProvider關系圖ContentProvider數據監聽觀察者注冊過程數據變化通知過程總結

前言

ContentService是Android四大組件之一的ContentProvider密切相關的一個系統服務,且和AccountManagerService也有著緊密的聯系。ContentService以功能來劃分,就兩大模塊:

提供管理通知監聽ContentProvider數據變化的觀察者的服務同步功能:同步日歷、Email等

第一個功能,對于很多開發者來說可能熟悉。而對于第二個,可能就會陌生一點,這個是Android提供的同步功能,很多APP開發者,也很難用到這個Android的同步功能。ContentService的同步功能和AccountManagerService往往緊密聯系在一起。本文將不再闡述ContentService的同步功能,有興趣的讀者可以自行閱讀Android的參考文檔了解該功能的使用方法https://developer.android.google.cn/reference/android/content/SyncRequest.html。那么本文將闡述的內容是:

ContentProvider的原理ContentProvider的觀察者服務

ContentProvider是Android的四大組件之一,是提供APP間安全共享數據的方式之一,APP可以通過ContentProvider從其它APP中獲取到想要的數據,例如讀取手機的聯系人。也可以通過ContentProvider把APP的數據共享出去給其它APP使用。

以查詢ContentProvider的數據的流程為線索,一步一步分析這個過程,從而了解ContentProvider的過程和原理。

APP發起查詢

引用官方的一段話:如果您想要訪問內容提供程序中的數據,可以將應用的 Context 中的 ContentResolver 對象用作客戶端來與提供程序通信。 ContentResolver 對象會與提供程序對象(即實現 ContentProvider 的類實例)通信。 提供程序對象從客戶端接收數據請求,執行請求的操作并返回結果。

APP發起查詢,很簡單,如下:

ContentResolver cr = getContentResolver();cr.query(Uri uri, ....);

首先通過getContentResolver()獲取到ContentResolver對象,ContentResolver對象好比內容分解器,能夠分解出來需要調用哪個內容提供程序即ContentProvider。ContentResolver分解的依據便是參數Uri。Uri是如何把ContentResolver和ContentProvider聯系起來的呢?Uri可以看作是一個地址描述,隨意舉一個Uri可描述的地址例子:

content://user_dictionary

可以和平時上網的網址做一個類比,如訪問百度:

https://www.baidu.com

Uri和網址結構有很大相似性,https表示的是網絡技術中的傳輸協議,那么content也可以當做ContentProvider中的一種協議,那么content就代表當前需要通過ContentProvider進行數據通信。www.baidu.com是百度的域名,表示需要訪問網站的位置,user_dictionary也就可以比作ContentProvider的域名,user_dictionary表示是那個ContentProvider。換句話說,ContentResolver接收到content://user_dictionary這個Uri時,就知道當前需要發起ContentProvider數據交互,通過user_dictionary可以尋找用user_dictionary表示的ContentProvider。

深入ContentResolver

準備工作

查看ContentResolver的定義,如下:

public abstract class ContentResolver { ......}

可見ContentResolver是一個抽象類,所以說getContentResolver()所獲取到實例本質是ContentResolver的子類,查看getContentResolver()的具體實現:

private final applicationContentResolver mContentResolver;public ContentResolver getContentResolver() { return mContentResolver;}

上面的代碼定義在文件frameworks/base/core/java/android/app/ContextImpl.java中

從上面的代碼可知,getContentResolver()獲取到的實際是ApplicationContentResolver的實例mContentResolver。cr.query(Uri uri, ….)的實現如下:

public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,......) { IContentProvider unstableProvider = acquireUnstableProvider(uri); ...... IContentProvider stableProvider = null; Cursor qCursor = null; try { ...... try { qCursor = unstableProvider.query(mPackageName, uri, projection, selection, selectionArgs, sortOrder, remoteCancellationSignal); } catch (DeadObjectException e) { unstableProviderDied(unstableProvider); stableProvider = acquireProvider(uri); if (stableProvider == null) { return null; } qCursor = stableProvider.query(mPackageName, uri, projection, selection, selectionArgs, sortOrder, remoteCancellationSignal); } if (qCursor == null) { return null; } ......}

這個方法定義在文件frameworks/base/core/java/android/content/ContentResolver.java中。

這里用文字描述一下上面代碼的過程,先聲明兩個相同類型的局部變量unstableProvider、stableProvider,都是IContentProvider的實例,IContentProvider是AIDL的接口,所以IContentProvider所調用的方法是遠程調用。通過acquireUnstableProvider()方法給unstableProvider變量賦值,unstableProvider調用query()方法,如果發生DeadObjectException異常,調用acquireProvider()方法給stableProvider賦值,然后調用stableProvider的query()方法。

這里有點奇怪,為什么要聲明兩個一樣的IContentProvider變量,且調用相同的方法query()。從變量的命名上,也能找到一點線索,unstableProvider和stableProvider,前者是不穩定的provider,后者是穩定的provider。什么樣表示穩定的,什么樣表示不穩定的?從上面的代碼來看,不穩定的provider,調用query()方法會拋出DeadObjectException。下面先看看unstableProvider的賦值過程:

public final IContentProvider acquireExistingProvider(......) { synchronized (mProviderMap) { final ProviderKey key = new ProviderKey(auth, userId); final ProviderClientRecord pr = mProviderMap.get(key); if (pr == null) { return null; } IContentProvider provider = pr.mProvider; IBinder jBinder = provider.asBinder(); ...... return provider; }}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

可見unstableProvider是從變量mProviderMap的實例中遍歷出來,也就是說,在調用者的進程內部,對provider會緩存到mProviderMap這個變量中。而IContentProvider是一個跨進程的遠程調用。換句話說,調用者的進程內部所緩存的unstableProvider實例所對應的遠程進程不能保證還正常運行著,如果所對應的遠程進程沒有運行,那么就會拋出DeadObjectException異常,并調用unstableProviderDied()方法把本地的緩存清除。然后通過acquireProvider()重新生產一個新的stableProvider,且Android系統會啟動和stableProvider對應的遠程進程,這個過程下文會闡述。可見Android這個舉措是為了性能考慮,目的讓APP的運行僅可能的快。

獲取ContentProvider

回到上文中實例化變量unstableProvider和stableProvider的代碼,unstableProvider或stableProvider實例化后,直接調用query()方法,然后直接就可以返回Cursor給調用者了,說明在這里的query()這一步,已經拿到調用者需要的數據。所以理解unstableProvider和stableProvider的實質至關重要。那么unstableProvider和stableProvider所對應的遠程進程的服務是哪一個呢?是不是就直接對應ContentProvider呢?

由于unstableProvider是一個調用者進程中緩存的實例,所以需要對stableProvider下手,了解stableProvider的實例化過程即可,如下:

public final IContentProvider acquireProvider(......) { ...... IActivityManager.ContentProviderHolder holder = null; try { holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ...... return holder.provider;}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

stableProvider被封裝到ContentProviderHolder的變量中provider中。通過調用ActivityManagerNative.getContentProvider()獲取ContentProviderHolder,ActivityManagerNative的所對應的遠程服務是system_process中的ActivityManagerService,接著看getContentProvider()這個方法:

public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) { ...... return getContentProviderImpl(caller, name, null, stable, userId);}

這個方法定義在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

這里直接調用了getContentProviderImpl()方法:

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null; synchronized(this) { ...... boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed; if (providerRunning) { ...... } if (!providerRunning) { ...... // If the provider is not already being launched, then get it // started. if (i >= N) { try { // Content provider is now in use, its package can't be stopped. ...... if (proc != null && proc.thread != null && !proc.killed) { ...... } else { proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false); ...... } cpr.launchingApp = proc; mLaunchingProviders.add(cpr); } finally { Binder.restoreCallingIdentity(origId); } } ...... mProviderMap.putProviderByName(name, cpr); conn = incProviderCountLocked(r, cpr, token, stable); if (conn != null) { conn.waiting = true; } } } // Wait for the provider to be published... synchronized (cpr) { while (cpr.provider == null) { ...... cpr.wait(); ...... } } return cpr != null ? cpr.newHolder(conn) : null;}

這個方法定義在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

由于這個方法的代碼篇幅非常大,這里省略了很多代碼,省略的代碼主要就是一些緩存、權限等等相關的代碼。這里假設provider的進程沒有啟動,從最原始,最干凈的時候分析ContentProvider的這個過程。聚焦上面的代碼,首先分兩種情況,providerRunning和!providerRunning,providerRunning是基于!providerRunning為前提的,因此provider第一次啟動是運行!providerRunning這個代碼路徑。假若provider沒有運行過,Android首先通過startProcessLocked()把provider所在的應用啟動起來,這個過程這里暫時先放下,繼續往下看,在最后面,有一個while循環,循環條件是cpr.provider == null?這里會一直等待cpr的provider變量被賦值,回到上文中的acquireProvider()方法的代碼,acquireProvider()首先要獲取的是ContentProviderHolder的實例,上面的代碼如果cpr != null,就返回一個ContentProviderHolder對象(cpr.newHolder(conn))。所以這里的cpr.provider就是上文中acquireProvider()需要獲取的IContentProvider的實例對象。

公布ContentProvider

因此,只要繼續分析清楚cpr.provider的賦值過程,就知道開始的時候ContentResolver.query()所調用的真正的遠程服務。回到上面的代碼,startProcessLocked()啟動應用時,運行到如下代碼(APP的啟動過程本文不再贅述):

public static void main(String[] args) { ...... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); ......}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

生成ActivityThread實例,也就是常說的主線程(UI線程了),然后調用attach()方法:

private void attach(boolean system) { ...... final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAPPThread); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ......}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

又回到ActivityManagerService了,接著往下看:

public final void attachApplication(IApplicationThread thread) { ...... attachApplicationLocked(thread, callingPid); ......}

這個方法定義在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

這里沒有需要看的代碼,繼續往下跟蹤:

private final boolean attachApplicationLocked(IApplicationThread thread,.....) { List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null; thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,......);}

這個方法定義在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

IApplicationThread實例thread是遠程APP的遠程調用端,所以thread.bindApplication()實際又從system_process進程回到了APP所在的進程,注意第三個參數providers,providers是封裝了應用的所有的ContentProvider,詳情讀者可以閱讀generateApplicationProvidersLocked(app)方法,本文不再闡述。繼續往下看:

public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName,......) { ...... data.providers = providers; data.compatInfo = compatInfo; data.initProfilerInfo = profilerInfo; sendMessage(H.BIND_APPLICATION, data);}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

發送了一個H.BIND_APPLICATION的消息,注意data.providers = providers。該消息的處理是在:

private void handleBindApplication(AppBindData data) {if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); ...... }}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

調用了installContentProviders()方法,注意參數data.providers,如下:

private void installContentProviders( Context context, List<ProviderInfo> providers) { final ArrayList<IActivityManager.ContentProviderHolder> results = new ArrayList<IActivityManager.ContentProviderHolder>(); for (ProviderInfo cpi : providers) { IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/); if (cph != null) { cph.noReleaseNeeded = true; results.add(cph); } } try { ActivityManagerNative.getDefault().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

把應用的所有的ContentProvider信息封裝到ContentProviderHolder中,這里要回到上文中acquireProvider()方法,獲取IContentProvider的實例正好是ContentProviderHolder的中的變量provider,因此,這里需要了解上面代碼ContentProviderHolder的實例cph的實例化過程,看installProvider()方法:

private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info,.....) { ContentProvider localProvider = null; IContentProvider provider; if (holder == null || holder.provider == null) { ...... try { final java.lang.ClassLoader cl = c.getClassLoader(); localProvider = (ContentProvider)cl. loadClass(info.name).newInstance(); provider = localProvider.getIContentProvider(); ...... IActivityManager.ContentProviderHolder retHolder; synchronized (mProviderMap) { IBinder jBinder = provider.asBinder(); if (localProvider != null) { ComponentName cname = new ComponentName(info.packageName, info.name); ProviderClientRecord pr = mLocalProvidersByName.get(cname); if (pr != null) { ...... } else { holder = new IActivityManager.ContentProviderHolder(info); holder.provider = provider; ...... } retHolder = pr.mHolder; } else { ...... return retHolder;}

這個方法定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

上面的代碼通過ClassLoader映射ContentProvider的對象實例,然后調用getIContentProvider()方法,獲取到IContentProvider的實例provider,然后賦值給ContentProviderHolder的實例holder的變量provider,所以provider正是acquireProvider()中獲取的的IContentProvider的實例,而繼續看getIContentProvider()方法查看provider的本質是:

......private Transport mTransport = new Transport();public IContentProvider getIContentProvider() { return mTransport;}class Transport extends ContentProviderNative { public Cursor query(.....){ ...... } ......}......

這個代碼定義在文件frameworks/base/core/java/android/content/ContentProvider.java中。

上面的代碼可見,provider實質是Transport的實例mTransport,Transport是ContentProviderNative的子類,而ContentProviderNative是IContentProvider的子類。

下面繼續看看provider和ActivityManagerService的關系,回到上文中的installContentProviders()方法,調用了publishContentProviders()方法,如下:

public final void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) { ...... final int N = providers.size(); for (int i = 0; i < N; i++) { ContentProviderHolder src = providers.get(i); if (src == null || src.info == null || src.provider == null) { continue; } ContentProviderRecord dst = r.pubProviders.get(src.info.name); if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid); if (dst != null) { ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name); mProviderMap.putProviderByClass(comp, dst); String names[] = dst.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.putProviderByName(names[j], dst); } ...... synchronized (dst) { dst.provider = src.provider; dst.proc = r; dst.notifyAll(); } } }}

這個代碼定義在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

把應用的ContentProvider信息緩存到mProviderMap中,這里重點關注語句dst.provider = src.provider,回到上文中getContentProviderImpl()方法中的代碼,后面的while循環,等待cpr.provider的賦值,dst.provider = src.provider正好就是這個賦值過程,cpr.provider賦值后,getContentProviderImpl()返回ContentProviderHolder的實例cpr.newHolder(conn),而這個實例持有變量provider指向Transport的實例mTransport,也就是應用的ContentProvider。

關系圖

這個過程非常繞亂人的頭緒,下面把這個過程簡單轉換成一張簡單的關系圖,理清這個過程和關系,如下:

這里寫圖片描述

ContentProvider數據監聽

觀察者注冊過程

有時APP開發的時候,APP運行時,需要實時監聽一些ContentProvider數據的變化。如用戶添加了一個聯系人,APP需要接收到聯系人添加的通知。由于ContentProvider的提供者,和需求者不是同一個APP,所以,這個通知的紐帶,就需要ContentService來完成。從注冊一個觀察者開始,分析這個通知的來龍去脈,注冊代碼如下:

ContentResolver cr = getContentResolver();cr.registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer);

當ContentProvider的數據發生變化時,便會回調到ContentObserver的onChange()方法,觀察者ContentObserver observer被注冊到哪里去呢?繼續進入分析:

public final void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer, @UserIdInt int userHandle) { try { getContentService().registerContentObserver(uri, notifyForDescendents, observer.getContentObserver(), userHandle); } catch (RemoteException e) { }}

這個方法定義在文件frameworks/base/core/java/android/content/ContentResolver.java中。

上面的代碼getContentService()獲取到的對象是:

public static IContentService getContentService() { if (sContentService != null) { return sContentService; } IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME); if (false) Log.v("ContentService", "default service binder = " + b); sContentService = IContentService.Stub.asInterface(b); if (false) Log.v("ContentService", "default service = " + sContentService); return sContentService;}

這個方法定義在文件frameworks/base/core/java/android/content/ContentResolver.java中。

閱讀《Android系統之System Server大綱 》可知,啟動的CONTENT_SERVICE_NAME的系統服務如下:

private static final String CONTENT_SERVICE_CLASS = "com.android.server.content.ContentService$Lifecycle";traceBeginAndSlog("StartContentService");mSystemServiceManager.startService(CONTENT_SERVICE_CLASS);Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

這個方法定義在文件frameworks/base/services/java/com/android/server/SystemServer.java中。

所以getContentService()獲取到的是ContentService,繼續往下分析registerContentObserver():

public void registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer, int userHandle) { ...... synchronized (mRootNode) { mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode, uid, pid, userHandle); if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + " with notifyForDescendants " + notifyForDescendants); }}

這個方法定義在文件frameworks/base/services/core/java/com/android/server/content/ContentService.java中。

上面的代碼把觀察者observer通過addObserverLocked放置在mRootNode對象中

private void addObserverLocked(Uri uri, int index, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle) { // If this is the leaf node add the observer if (index == countUriSegments(uri)) { mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock, uid, pid, userHandle)); return; } // Look to see if the proper child already exists String segment = getUriSegment(uri, index); int N = mChildren.size(); for (int i = 0; i < N; i++) { ObserverNode node = mChildren.get(i); if (node.mName.equals(segment)) { node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, observersLock, uid, pid, userHandle); return; } } // No child found, create one ObserverNode node = new ObserverNode(segment); mChildren.add(node); node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, observersLock, uid, pid, userHandle); }

這個方法定義在文件frameworks/base/services/core/java/com/android/server/content/ContentService.java中。

首先把觀察者observer再次封裝到mObservers中,mObservers是ArrayList的實例,后面依次遍歷整個需要監聽的Uri,用segment生產一個ObserverNode實例,保存在ArrayList的實例mChildren中。

觀察者都被封裝好以后,就等待數據的變化了。在上文ContentProvider的原理中,可知,ContentProvider的需求者拿到ContentProvider提供者的遠程調用后,兩個APP直接進行交互了,任何數據變化并沒有經過ContentService,因此,ContentService是如何監測ContentProvider數據發生變化并通知到觀察者呢?這里的機制便是ContentProvider提供者的數據發生變化時,ContentProvider提供者必須主動通過notifyChange()方法通知ContentService數據發生了變化。下面以聯系人的數據庫變化為例,闡述這個過程。

數據變化通知過程

添加一個聯系人,調用ContactsProvider的insert()方法,如下:

public Uri insert(Uri uri, ContentValues values) { incrementStats(mInsertStats, mInsertInBatchStats); ContactsTransaction transaction = startTransaction(false); try { Uri result = insertInTransaction(uri, values); if (result != null) { transaction.markDirty(); } transaction.markSuccessful(false); return result; } finally { endTransaction(false); }}

這個方法定義在文件packages/providers/ContactsProvider/src/com/android/providers/contacts/AbstractContactsProvider.java中。

上面的代碼中,一次插入的業務抽象成一個ContactsTransaction,然后調用insertInTransaction()方法把數據插入數據庫成功后,調用transaction.markDirty()標記當前的數據狀態有變化,然后調用endTransaction()結束當前的業務。如下:

private void endTransaction(boolean callerIsBatch) { ContactsTransaction transaction = mTransactionHolder.get(); if (transaction != null && (!transaction.isBatch() || callerIsBatch)) { boolean notify = false; try { if (transaction.isDirty()) { notify = true; } transaction.finish(callerIsBatch); if (notify) { notifyChange(); } } finally { // No matter what, make sure we clear out the thread-local transaction reference. mTransactionHolder.set(null); } }}

這個方法定義在文件packages/providers/ContactsProvider/src/com/android/providers/contacts/AbstractContactsProvider.java中。

上面的代碼,通過mTransactionHolder.get()獲取剛剛進行的業務transaction,如果的這個業務被標記為markDirty(),transaction.isDirty()返回true,所以notify被置成true,所以會調用notifyChange()。往下看這個方法:

protected void notifyChange(boolean syncToNetwork, boolean syncToMetadataNetwork) { getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, syncToNetwork); getContext().getContentResolver().notifyChange(MetadataSync.METADATA_AUTHORITY_URI, null, syncToMetadataNetwork);}

這個方法定義在文件packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java中。

上面的代碼,獲取到ContentResolver()對象,和query()類似,然后調用notifyChange()通知ContentResolver數據發生了變化,如下:

public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork, @UserIdInt int userHandle) { try { getContentService().notifyChange( uri, observer == null ? null : observer.getContentObserver(), observer != null && observer.deliverSelfNotifications(), syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0, userHandle); } catch (RemoteException e) { }}

這個方法定義在文件frameworks/base/core/java/android/content/ContentResolver.java中。

上面的代碼調用getContentService()方法,從上文可知,getContentService()獲取到的是ContentService的遠程調用,因此getContentService().notifyChange()實質會運行到ContentService的notifyChange()方法,如下:

public void notifyChange(Uri uri, ......) { ...... try { ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); synchronized (mRootNode) { mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications, flags, userHandle, calls); } final int numCalls = calls.size(); for (int i=0; i<numCalls; i++) { ObserverCall oc = calls.get(i); try { oc.mObserver.onChange(oc.mSelfChange, uri, userHandle); } catch (RemoteException ex) { ...... } } ...... } } finally { restoreCallingIdentity(identityToken); }}

這個方法定義在文件frameworks/base/services/core/java/com/android/server/content/ContentService.java中。

上面的代碼中的mRootNode變量,在注冊觀察者的章節中,mRootNode封裝了所有的觀察者。調用collectObserversLocked()根據觀察者監聽的Uri類型把觀察者封裝到ArrayList的實例calls中,然后調用oc.mObserver.onChange()方法通知APP數據發生變化。

總結

本文詳細闡述了ContentProvider的原理,從ContentProvider的query過程入手,全面詳細分析了從query()的發起APP到ActivityManagerService,再到ContentProvider提供程序的整個流程和交互過程。以及分析了ContentService在ContentProvider的數據變化監測通知的架構中,扮演了觀察者模式中的抽象主題,具體主題部分。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 临武县| 嘉义县| 岳普湖县| 东山县| 凌源市| 三江| 惠安县| 合阳县| 宜城市| 克山县| 元谋县| 鄢陵县| 彭水| 二连浩特市| 康乐县| 东方市| 丽江市| 应用必备| 呼和浩特市| 龙口市| 天全县| 宁德市| 离岛区| 青阳县| 日土县| 孟津县| 即墨市| 普兰县| 秀山| 天峨县| 海阳市| 盐边县| 夏津县| 洞口县| 鹤岗市| 博爱县| 镇沅| 昭平县| 佛坪县| 富民县| 昭通市|