ContentProvider是内容提供者,能够跨进程提供数据。

咱们都知道,ContentProvider的发动,是在Application的onCreate办法之前的,所以ContentProvider的初始化时刻会影响整个App的发动速度。

ContentProvider发动流程具体是什么样的呢?让咱们进入源码的世界来一探终究。

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的发动。