ContentProvider啟動流程示例解析

正文

ContentProvider是內容提供者,可以跨進程提供數據。

大傢都知道,ContentProvider的啟動,是在Application的onCreate方法之前的,所以ContentProvider的初始化時間會影響整個App的啟動速度。

ContentProvider啟動流程具體是什麼樣的呢?讓我們進入源碼的世界來一探究竟。

App啟動

App啟動時,AMS會通過跨進程Binder調用,訪問到ApplicationThread種的bindApplication方法。

      public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, boolean autofillCompatibilityEnabled) {
            // 拼接AppBindData,發送給ActivityThread的H
            sendMessage(H.BIND_APPLICATION, data);
        }

這個方法主要作用是,拼接AppBindData,發送給ActivityThread中的Handler mH。在這個Handler中,會處理Message,然後調用handleBindApplication(data)方法。

private void handleBindApplication(AppBindData data) {
    final InstrumentationInfo ii;
    // 創建 mInstrumentation 實例
    if (ii != null) {
        //創建ContextImpl
        final ContextImpl appContext = ContextImpl.createAppContext(this, pi);
        try {
            //創建mInstrumentation實例
            final ClassLoader cl = appContext.getClassLoader();
            mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        } catch (Exception e) {}
    } else {
        mInstrumentation = new Instrumentation();
    }
    Application app;
    try {
        // 創建 Application 實例
        app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
        // 如果不是backup模式,則調用installContentProvider,啟動ContentProvider
         if (!data.restrictedBackupMode) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    //啟動ContentProvider
                    installContentProviders(app, data.providers);
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                }
            }
        try {
            //調用Application的onCreate
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) { }
    }
}

這個方法非常長,主要做的事情有以下四點:

  • 創建一個ContentImpl對象
  • 創建一個Instrument對象
  • 創建Application實例
  • 如果不是backup模式,調用installContentProviders,啟動ContentProvider
  • 調用ApplicationonCreate方法

installContentProviders

private void installContentProviders(Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();
        // 遍歷所有的providers
        for (ProviderInfo cpi : providers) {
            // 開始啟動ContentProvider
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
             results.add(cph);
        }
        // 將成功啟動的provider存儲到AMS的mProviderMap中
        ActivityManager.getService().publishContentProviders(getApplicationThread(), results);
    }

這個方法,循環遍歷所有待啟動的ContentProvider,調用installProvider啟動。

 private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
                // 反射創建ContentProvider
                final java.lang.ClassLoader cl = c.getClassLoader();
                LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
                localProvider = cl.loadClass(className).newInstance();
                provider = localProvider.getIContentProvider();
                // 調用ContentProvider的attachInfo方法
                localProvider.attachInfo(c, info);
    }

這個方法,通過反射創建ContentProvider,然後調用attachInfo方法。

 private void attachInfo(Context context, ProviderInfo info, boolean testing) {
        // 調用onCreate方法
       ContentProvider.this.onCreate();
}

ContentProviderattachInfo方法中,會調用onCreate方法,完成ContentProvider的啟動。

以上就是ContentProvider啟動流程示例解析的詳細內容,更多關於ContentProvider啟動流程的資料請關註WalkonNet其它相關文章!

推薦閱讀: