本文分析的代码版本为Android 6.0
一 使用资源id加载加载图片流程
在Activity或Fragment中常使用getResources().getDrawable()加载图片资源。getResources和getDrawable方法的调用需要经过哪些步骤和流程。
1 与Context相关的步骤
ContextThemeWrapper的
@Override
public Resources getResources() {
return getResourcesInternal();
}
private Resources getResourcesInternal() {
if (mResources == null) {
if (mOverrideConfiguration == null) {
mResources = super.getResources();
} else {
final Context resContext = createConfigurationContext(mOverrideConfiguration);
mResources = resContext.getResources();
}
}
return mResources;
}
只分析mOverrideConfiguration==null条件下如何获取resource。super.getResources()调用的是ContextWrapper的方法,而ContextWrapper调用的是mBase.getResources()。mBase是ContextImpl实例,在Activity被ActivityThread创建时,通过Activity的attach()方法赋值给Activity的。Activity和ContextImpl的创建和赋值过程这里就不分析了。
ContextImpl的getResources()方法:
@Override
public Resources getResources() {
return mResources;
}
而mResources是在ContextImpl的私有构造方法内创建的。
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
…//省略部分无关代码
mMainThread = mainThread;
mActivityToken = activityToken;
mFlags = flags;
if (user == null) {
user = Process.myUserHandle();
}
mUser = user;
mPackageInfo = packageInfo;
mResourcesManager = ResourcesManager.getInstance();
final int displayId = (createDisplayWithId != Display.INVALID_DISPLAY)
? createDisplayWithId
: (display != null) ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
CompatibilityInfo compatInfo = null;
if (container != null) {
compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
}
if (compatInfo == null) {
compatInfo = (displayId == Display.DEFAULT_DISPLAY)
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
}
//创建
Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
if (displayId != Display.DEFAULT_DISPLAY
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
if (container != null) {
// This is a nested Context, so it can't be a base Activity context.
// Just create a regular Resources object associated with the Activity.
resources = mResourcesManager.getResources(
activityToken,
packageInfo.getResDir(),
packageInfo.getSplitResDirs(),
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
packageInfo.getClassLoader());
} else {
// This is not a nested Context, so it must be the root Activity context.
// All other nested Contexts will inherit the configuration set here.
//创建Activity的Context时的赋值流程
resources = mResourcesManager.createBaseActivityResources(
activityToken,
packageInfo.getResDir(),
packageInfo.getSplitResDirs(),
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
packageInfo.getClassLoader());
}
}
}
mResources = resources;
…//省略部分无关代码
}
这里就不分析packageInfo.getResources,mResourcesManager.getResources和mResourcesManager.createBaseActivityResources如何创建Resources。
2 Resources和ResourcesImpl中的步骤
继续看Resources#getDrawable: