问题:
ContentProvider是什么时候初始化的?
回答:
在ActivityThread的handleBindApplication方法中调用installContentProviders完成ContentProvider的初始化,其初始化时机在Application的attachBaseContext之后,优先于Application的onCreate方法
解析:
为了跟踪ContentProvider onCreate的调用堆栈,我们自定义MyContentProvider类,并在其onCreate函数中打印堆栈,随后运行可以看到打印日志如下图所示:
日志打印堆栈与我们上文中回答的调用次序一致,那么如何得出它的执行顺序晚于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的初始化流程如下图所示: