<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### 9.5 ContentProvider的工作過程 ContentProvider的使用方法在第2章已經做了介紹,這里再簡單說明一下。ContentProvider是一種內容共享型組件,它通過Binder向其他組件乃至其他應用提供數據。當ContentProvider所在的進程啟動時,ContentProvider會同時啟動并被發布到AMS中。需要注意的是,這個時候ContentProvider的onCreate要先于Application的onCreate而執行,這在四大組件中是一個少有的現象。 當一個應用啟動時,入口方法為ActivityThread的main方法,main方法是一個靜態方法,在main方法中會創建ActivityThread的實例并創建主線程的消息隊列,然后在ActivityThread的attach方法中會遠程調用AMS的attachApplication方法并將ApplicationThread對象提供給AMS。ApplicationThread是一個Binder對象,它的Binder接口是IApplicationThread,它主要用于ActivityThread和AMS之間的通信,這一點在前面多次提到。在AMS的attachApplication方法中,會調用ApplicationThread的bindApplication方法,注意這個過程同樣是跨進程完成的,bindApplication的邏輯會經過ActivityThread中的mH Handler切換到ActivityThread中去執行,具體的方法是handleBindApplication。在handleBindApplication方法中,ActivityThread會創建Application對象并加載ContentProvider。需要注意的是,ActivityThread會先加載ContentProvider,然后再調用Application的onCreate方法,整個流程可以參看圖9-2。 :-: ![](https://img.kancloud.cn/6c/c4/6cc495d284fda3440665db220df8050c_990x602.png) 圖9-2 ContentProvider的啟動過程 這就是ContentProvider的啟動過程,ContentProvider啟動后,外界就可以通過它所提供的增刪改查這四個接口來操作ContentProvider中的數據源,即insert、delete、update和query四個方法。這四個方法都是通過Binder來調用的,外界無法直接訪問ContentProvider,它只能通過AMS根據Uri來獲取對應的ContentProvider的Binder接口IConentProvider,然后再通過IConentProvider來訪問ContentProvider中的數據源。 一般來說,ContentProvider都應該是單實例的。ContentProvider到底是不是單實例,這是由它的android:multiprocess屬性來決定的,當android:multiprocess為false時,ContentProvider是單實例,這也是默認值;當android:multiprocess為true時,ContentProvider為多實例,這個時候在每個調用者的進程中都存在一個ContentProvider對象。由于在實際的開發中,并未發現多實例的ContentProvider的具體使用場景,官方文檔中的解釋是這樣可以避免進程間通信的開銷,但是這在實際開發中仍然缺少使用價值。因此,我們可以簡單認為ContentProvider都是單實例的。下面分析單實例的ContentProvider的啟動過程。 訪問ContentProvider需要通過ContentResolver, ContentResolver是一個抽象類,通過Context的getContentResolver方法獲取的實際上是ApplicationContentResolver對象,ApplicationContentResolver類繼承了ContentResolver并實現了ContentResolver中的抽象方法。當ContentProvider所在的進程未啟動時,第一次訪問它時就會觸發ContentProvider的創建,當然這也伴隨著ContentProvider所在進程的啟動。通過ContentProvider的四個方法的任何一個都可以觸發ContentProvider的啟動過程,這里選擇query方法。 ContentProvider的query方法中,首先會獲取IContentProvider對象,不管是通過acquireUnstableProvider方法還是直接通過acquireProvider方法,它們的本質都是一樣的,最終都是通過acquireProvider方法來獲取ContentProvider。下面是ApplicationContent-Resolver的acquireProvider方法的具體實現: protected IContentProvider acquireProvider(Context context, String auth) { return mMainThread.acquireProvider(context, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), true); } ApplicationContentResolver的acquireProvider方法并沒有處理任何邏輯,它直接調用了ActivityThread的acquireProvider方法,ActivityThread的acquireProvider方法的源碼如下所示。 public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider ! = null) { return provider; } // There is a possible race here. Another thread may try to acquire // the same provider at the same time. When this happens, we want to ensure // that the first one wins. // Note that we cannot hold the lock while acquiring and installing the // provider since it might take a long time to run and it could also potentially // be re-entrant in the case where the provider is in the same process. IActivityManager.ContentProviderHolder holder = null; try { holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { } if (holder == null) { Slog.e(TAG, "Failed to find provider info for " + auth); return null; } // Install provider will increment the reference count for us, and break // any ties in the race. holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable); return holder.provider; } 上面的代碼首先會從ActivityThread中查找是否已經存在目標ContentProvider了,如果存在就直接返回。ActivityThread中通過mProviderMap來存儲已經啟動的ContentProvider對象,mProviderMap的聲明如下所示。 final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<ProviderKey, ProviderClientRecord>(); 如果目前ContentProvider沒有啟動,那么就發送一個進程間請求給AMS讓其啟動目標ContentProvider,最后再通過installProvider方法來修改引用計數。那么AMS是如何啟動ContentProvider的呢?我們知道,ContentProvider被啟動時會伴隨著進程的啟動,在AMS中,首先會啟動ContentProvider所在的進程,然后再啟動ContentProvider。啟動進程是由AMS的startProcessLocked方法來完成的,其內部主要是通過Process的start方法來完成一個新進程的啟動,新進程啟動后其入口方法為ActivityThread的main方法,如下所示。 public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(User- Handle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } 可以看到,ActivityThread的main方法是一個靜態方法,在它內部首先會創建Activity-Thread的實例并調用attach方法來進行一系列初始化,接著就開始進行消息循環了。ActivityThread的attach方法會將ApplicationThread對象通過AMS的attachApplication方法跨進程傳遞給AMS,最終AMS會完成ContentProvider的創建過程,源碼如下所示。 try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { // Ignore } AMS的attachApplication方法調用了attachApplicationLocked方法,attachApplication-Locked中又調用了ApplicationThread的bindApplication,注意這個過程也是進程間調用,如下所示。 thread.bindApplication(processName, appInfo, providers, app.instrumen- tationClass, profilerInfo, app.instrumentationArguments, app.instrumentation- Watcher, app.instrumentationUiAutomationConnection, testMode, enableOpen- GlTrace, isRestrictedBackupMode || ! normalMode, app.persistent, new Configuration(mConfiguration), app.compat, getCommonServices- Locked(), mCoreSettingsObserver.getCoreSettingsLocked()); ActivityThread的bindApplication會發送一個BIND_APPLICATION類型的消息給mH, mH是一個Handler,它收到消息后會調用ActivityThread的handleBindApplication方法,bindApplication發送消息的過程如下所示。 AppBindData data = new AppBindData(); data.processName = processName; data.appInfo = appInfo; data.providers = providers; data.instrumentationName = instrumentationName; data.instrumentationArgs = instrumentationArgs; data.instrumentationWatcher = instrumentationWatcher; data.instrumentationUiAutomationConnection = instrumentationUiConnection; data.debugMode = debugMode; data.enableOpenGlTrace = enableOpenGlTrace; data.restrictedBackupMode = isRestrictedBackupMode; data.persistent = persistent; data.config = config; data.compatInfo = compatInfo; data.initProfilerInfo = profilerInfo; sendMessage(H.BIND_APPLICATION, data); ActivityThread的handleBindApplication則完成了Application的創建以及Content-Provider的創建,可以分為如下四個步驟。 1.創建ContextImpI和Instrumentation ContextImpl instrContext = ContextImpl.createAppContext(this, pi); try { java.lang.ClassLoader cl = instrContext.getClassLoader(); mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance(); } catch (Exception e) { throw new RuntimeException( "Unable to instantiate instrumentation " + data.instrumentationName + ": " + e.toString(), e); } mInstrumentation.init(this, instrContext, appContext, new ComponentName(ii.packageName, ii.name), data.instrumentation- Watcher, data.instrumentationUiAutomationConnection); 2.創建AppIication對象 Application app = data.info.makeApplication(data.restrictedBackupMode, null); mInitialApplication = app; 3.啟動當前進程的ContentProvider并調用其onCreate方法 List<ProviderInfo> providers = data.providers; if (providers ! = null) { installContentProviders(app, providers); // For process that contains content providers, we want to // ensure that the JIT is enabled "at some point". mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); } installContentProviders完成了ContentProvider的啟動工作,它的實現如下所示。首先會遍歷當前進程的ProviderInfo的列表并一一調用調用installProvider方法來啟動它們,接著將已經啟動的ContentProvider發布到AMS中,AMS會把它們存儲在ProviderMap中,這樣一來外部調用者就可以直接從AMS中獲取ContentProvider了。 private void installContentProviders( Context context, List<ProviderInfo> providers) { final ArrayList<IActivityManager.ContentProviderHolder> results = new ArrayList<IActivityManager.ContentProviderHolder>(); for (ProviderInfo cpi : providers) { if (DEBUG_PROVIDER) { StringBuilder buf = new StringBuilder(128); buf.append("Pub "); buf.append(cpi.authority); buf.append(": "); buf.append(cpi.name); Log.i(TAG, buf.toString()); } 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) { } } 下面看一下ContentProvider對象的創建過程,在installProvider方法中有下面一段代碼,其通過類加載器完成了ContentProvider對象的創建: final java.lang.ClassLoader cl = c.getClassLoader(); localProvider = (ContentProvider)cl. loadClass(info.name).newInstance(); provider = localProvider.getIContentProvider(); if (provider == null) { Slog.e(TAG, "Failed to instantiate class " + info.name + " from sourceDir " + info.applicationInfo.sourceDir); return null; } if (DEBUG_PROVIDER) Slog.v( TAG, "Instantiating local provider " + info.name); // XXX Need to create the correct context for this provider. localProvider.attachInfo(c, info); 在上述代碼中,除了完成ContentProvider對象的創建,還會通過ContentProvider的attachInfo方法來調用它的onCreate方法,如下所示。 private void attachInfo(Context context, ProviderInfo info, boolean testing) { ... if (mContext == null) { mContext = context; if (context ! = null) { mTransport.mAppOpsManager = (AppOpsManager) context.getSystem- Service( Context.APP_OPS_SERVICE); } mMyUid = Process.myUid(); ... ContentProvider.this.onCreate(); } } 到此為止,ContentProvider已經被創建并且其onCreate方法也已經被調用,這意味著ContentProvider已經啟動完成了。 4.調用AppIication的onCreate方法 try { mInstrumentation.callApplicationOnCreate(app); } catch (Exception e) { if (! mInstrumentation.onException(app, e)) { throw new RuntimeException( "Unable to create application " + app.getClass().getName() + ": " + e.toString(), e); } } 經過上面的四個步驟,ContentProvider已經成功啟動,并且其所在進程的Application也已經啟動,這意味著ContentProvider所在的進程已經完成了整個的啟動過程,然后其他應用就可以通過AMS來訪問這個ContentProvider了。拿到了ContentProvider以后,就可以通過它所提供的接口方法來訪問它了。需要注意的是,這里的ContentProvider并不是原始的ContentProvider,而是ContentProvider的Binder類型的對象IContentProvider, IContentProvider的具體實現是ContentProviderNative和ContentProvider.Transport,其中ContentProvider.Transport繼承了ContentProviderNative。這里仍然選擇query方法,首先其他應用會通過AMS獲取到ContentProvider的Binder對象即IContentProvider,而IContentProvider的實現者實際上是ContentProvider.Transport。因此其他應用調用IContentProvider的query方法時最終會以進程間通信的方式調用到ContentProvider. Transport的query方法,它的實現如下所示。 public Cursor query(String callingPkg, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal) { validateIncomingUri(uri); uri = getUriWithoutUserId(uri); if (enforceReadPermission(callingPkg, uri) ! = AppOpsManager.MODE_ ALLOWED) { return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.query( uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } finally { setCallingPackage(original); } } 很顯然,ContentProvider.Transport的query方法調用了ContentProvider的query方法,query方法的執行結果再通過Binder返回給調用者,這樣一來整個調用過程就完成了。除了query方法,insert、delete和update方法也是類似的,這里就不再分析了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看