面试串讲010-ContentProvider初始化时机

55 阅读1分钟

问题:

ContentProvider是什么时候初始化的?

回答:

在ActivityThread的handleBindApplication方法中调用installContentProviders完成ContentProvider的初始化,其初始化时机在Application的attachBaseContext之后,优先于Application的onCreate方法

解析:

为了跟踪ContentProvider onCreate的调用堆栈,我们自定义MyContentProvider类,并在其onCreate函数中打印堆栈,随后运行可以看到打印日志如下图所示:

mianshi010-1

日志打印堆栈与我们上文中回答的调用次序一致,那么如何得出它的执行顺序晚于Application.attachBaseContext,优先于Application.Context呢?

看一下ActivityThread.handleBindApplication源码即可

 private void handleBindApplication(AppBindData data) {
     ...
     try {
         // 调用Application.attachBaseContext
         app = data.info.makeApplication(data.restrictedBackupMode, null);
         ...
         if (!data.restrictedBackupMode) {
             if (!ArrayUtils.isEmpty(data.providers)) {
                 // 初始化ContentProvider
                 installContentProviders(app, data.providers);
             }
         }
 ​
         try {
             mInstrumentation.onCreate(data.instrumentationArgs);
         } catch (Exception e) {
           ...
         }
         try {
             // 调用Application.onCreate
             mInstrumentation.callApplicationOnCreate(app);
         } catch (Exception e) {
           ...
         }
     } finally {
       ...
     }
 ​
     ...
 }

Application.onCreate和installContentProviders的调用显而易见,接下来我们大概介绍一下Application.attachBaseContext的调用顺序

Application.attachBaseContext

data.info是LoadedApk类的实例对象,其makeApplication代码如下所示:

 public Application makeApplication(boolean forceDefaultAppClass,
         Instrumentation instrumentation) {
     ...
     try {
         ...
         NetworkSecurityConfigProvider.handleNewApplication(appContext);
         // 调用Instrumentation.newApplication
         app = mActivityThread.mInstrumentation.newApplication(
                 cl, appClass, appContext);
         appContext.setOuterContext(app);
     } catch (Exception e) {
       ...
     }
     ...
     return app;
 }

Instrumentation.newApplication代码如下所示:

 public Application newApplication(ClassLoader cl, String className, Context context)
         throws InstantiationException, IllegalAccessException, 
         ClassNotFoundException {
     Application app = getFactory(context.getPackageName())
             .instantiateApplication(cl, className);
     app.attach(context);
     return app;
 }

在Application.attach方法中会调用attachBaseContext。

ContentProvider初始化流程

综上ContentProvider的初始化流程如下图所示:

contentprovider_create_process.drawio