当前位置:网站首页>Source code analysis | resource loading resources
Source code analysis | resource loading resources
2022-07-03 02:41:00 【Nuggets】
Understand the loading process of resources , Realize loading the resource file in the skin file
Resource loading
imageView In the layout src How is the picture loaded ?
mResources.loadDrawable(value, value.resourceId, density, mTheme)
It's all through Resource Loading
Since resources are loaded through Resource class , If you want to get another apk Resource files in , Then instantiate one by yourself Resource Can I load it ?
- The first thing to know is that Resource How to instantiate
@Override
public Resources getResources() {
if (mResources == null && VectorEnabledTintResources.shouldBeUsed()) {
mResources = new VectorEnabledTintResources(this, super.getResources());
}
return mResources == null ? super.getResources() : mResources;
} stay AppcompatActivity in , There is one getResources Method to get Resource. If mResource by null, Then what is called is super.Resources().
@Override
public Resources getResources() {
return getResourcesInternal();
}
private Resources getResourcesInternal() {
if (mResources == null) {
if (mOverrideConfiguration == null) {
//1
mResources = super.getResources();
} else {
final Context resContext = createConfigurationContext(mOverrideConfiguration);
//2
mResources = resContext.getResources();
}
}
return mResources;
}above 1 and 2 In the end, what is called is Context Of getResource Method , however Context Of getResource It's an abstract method , We have to find his implementation class .
// Returns the... Of the application package Resources example public abstract Resources getResources();
His implementation class is actually ContextImpl , This class is in the as You can't see it above , You need to check from the source code
@Override
public Resources getResources() {
return mResources;
}Finally, the above method is called , as for mResource How to instantiate , as follows :
private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName,
int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) {
final String[] splitResDirs;
final ClassLoader classLoader;
try {
splitResDirs = pi.getSplitPaths(splitName);
classLoader = pi.getSplitClassLoader(splitName);
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
return ResourcesManager.getInstance().getResources(activityToken,
pi.getResDir(),
splitResDirs,
pi.getOverlayDirs(),
pi.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfig,
compatInfo,
classLoader);
}establish Resource Will go to createResources Method .
You can see that the final call is ResourcesManager Of getResource Method ,
public @Nullable Resources getResources(@Nullable IBinder activityToken,
@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@Nullable String[] libDirs,
int displayId,
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
final ResourcesKey key = new ResourcesKey(
resDir,
splitResDirs,
overlayDirs,
libDirs,
displayId,
overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
compatInfo);
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
return getOrCreateResources(activityToken, key, classLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}among Parameters resDir Namely apk Storage path . In this way Parameters are integrated into ResourceKey in , And then it calls getOrCreateResources Method
private @Nullable Resources getOrCreateResources(@Nullable IBinder activityToken,
@NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
ynchronized (this) {
// From the cache ResourcesImpl
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
if (resourcesImpl != null) {
if (DEBUG) {
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
}
//1
return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
resourcesImpl, key.mCompatInfo);
}
} else {
// Clean up any dead references so they don't pile up.
ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
// Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
if (resourcesImpl != null) {
if (DEBUG) {
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
}
//2
return getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
}
// We will create the ResourcesImpl object outside of holding this lock.
}
// If not, create
ResourcesImpl resourcesImpl = createResourcesImpl(key);
if (resourcesImpl == null) {
return null;
}
// Join the cache
mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
final Resources resources;
if (activityToken != null) {
//3
resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
resourcesImpl, key.mCompatInfo);
} else {
//4
resources = getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
}
return resources;
}
}
Look for the mark Of 1,2,3,4 , These four locations call two methods , These two methods will eventually be created through the following sentence Resource
// Create a new resource reference and use the existing ResourcesImpl object
Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
: new Resources(classLoader);
resources.setImpl(impl);Come here Resources It was created successfully
We just need to know Resource Just how to instantiate , What is it? new Coming out .
- Resources Constructor for
@Deprecated
public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
this(null);
mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());
}
@UnsupportedAppUsage
public Resources(@Nullable ClassLoader classLoader) {
mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
}Resources Construction method , Because of the source code Different versions ,new Resource The structure may also be different . It looks a little different , But it's almost , stay new Resources Next line , Called setImpl Method , Incoming ResourcesImpl Actually by createResourcesImpl Method :
private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
daj.setCompatibilityInfo(key.mCompatInfo);
final AssetManager assets = createAssetManager(key);
//.....
final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
final Configuration config = generateConfig(key, dm);
final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
return impl;
}Through the top Method to create ResourceImpl, In fact, it is similar to that created in the first construction method .
- ResourceImpl
structure :new ResourcesImpl(assets, dm, config, daj);
- assets: AssetManager Resource management , Create as follows , adopt Builder establish AssetManager object , And passed in various paths , In some versions of the source code AssetManager It's direct new Coming out , And called addAssetPath Methods the incoming apk route
protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
final AssetManager.Builder builder = new AssetManager.Builder();
// resDir can be null if the 'android' package is creating a new Resources object.
// This is fine, since each AssetManager automatically loads the 'android' package
// already.
if (key.mResDir != null) {
//mResDir:apk The catalog of
builder.addApkAssets(loadApkAssets(key.mResDir, false /*sharedLib*/, false /*overlay*/));
}
if (key.mSplitResDirs != null) {
for (final String splitResDir : key.mSplitResDirs) {
builder.addApkAssets(loadApkAssets(splitResDir, false /*sharedLib*/,
false /*overlay*/));
}
}
if (key.mOverlayDirs != null) {
for (final String idmapPath : key.mOverlayDirs) {
builder.addApkAssets(loadApkAssets(idmapPath, false /*sharedLib*/,
true /*overlay*/));
}
}
if (key.mLibDirs != null) {
for (final String libDir : key.mLibDirs) {
if (libDir.endsWith(".apk")) {
builder.addApkAssets(loadApkAssets(libDir, true /*sharedLib*/,
false /*overlay*/));
}
}
}
return builder.build();
}Resource loading summary : All resources are loaded through Resource ,Resource -> When building objects of new The object of ,-> There is a very important parameter AssetManager, This class is time Resource Core examples .
And finally through AssetManager obtain .
Create by yourself Resources Load the resource file in the skin file
1, Understand skin files
Skin file is actually a apk, Add resource files to the project , Then generate a apk, Then this apk Is the skin file , The resources in the skin file must be consistent with those in the project .
2, adopt Resources Get the resource file in the skin file , And load
val superRes = resources
// Create reflection AssetManager, Construction is hidden , You can't create
val assetManager = AssetManager::class.java.newInstance()
// Reflection method , Add locally downloaded resources apk Catalog ,apk The suffix of can be changed at will , This is changed to .skin
val method =
AssetManager::class.java.getDeclaredMethod("addAssetPath", String::class.java)
method.invoke(
assetManager, "${Environment.getExternalStorageDirectory().absolutePath}${File.separator}red.skin"
)
// Create a Resource, The specific methods are in the source code , We've already talked about that .
// The parameters created are all in the source code , Just copy it
val resources = Resources(assetManager, superRes.displayMetrics, superRes.configuration)
//1, Resource name , The resource type , Package name
val drawableId = resources.getIdentifier("image_src", "drawable", "com.qs.redskin")
// obtain resources
val drawable = resources.getDrawable(drawableId)
mImageView.setImageDrawable(drawable)Through the above steps, you can load In the skin The resource file has . Be careful to apply for Storage rights
The above is just a simple Demo
边栏推荐
- Xiaodi notes
- Tongda OA homepage portal workbench
- sql server 查询指定表的表结构
- Gbase 8C system table PG_ cast
- 【Flutter】shared_ Preferences local storage (introduction | install the shared_preferences plug-in | use the shared_preferences process)
- Apple releases MacOS 11.6.4 update: mainly security fixes
- 定了,就选它
- Kubernetes family container housekeeper pod online Q & A?
- awk从入门到入土(2)认识awk内置变量和变量的使用
- 【教程】chrome關閉跨域策略cors、samesite,跨域帶上cookie
猜你喜欢

【翻译】后台项目加入了CNCF孵化器

SQL statement

What is the way out for children from poor families?

Kubernetes family container housekeeper pod online Q & A?
[advanced ROS] Lesson 6 recording and playback in ROS (rosbag)

sql server数据库添加 mdf数据库文件,遇到的报错

Summary of interview project technology stack

Random shuffle note

A2L file parsing based on CAN bus (2)

Xiaodi notes
随机推荐
SQL statement
leetcode540
GBase 8c触发器(二)
Apple releases MacOS 11.6.4 update: mainly security fixes
定了,就选它
Tongda OA homepage portal workbench
awk从入门到入土(1)awk初次会面
Gbase 8C system table PG_ cast
Gbase 8C system table PG_ aggregate
搭建私有云盘 cloudreve
【教程】chrome關閉跨域策略cors、samesite,跨域帶上cookie
面试项目技术栈总结
[advanced ROS] Lesson 6 recording and playback in ROS (rosbag)
错误Invalid bound statement (not found): com.ruoyi.stock.mapper.StockDetailMapper.xxxx解决
Didi programmers are despised by relatives: an annual salary of 800000 is not as good as two teachers
Matlab tips (24) RBF, GRNN, PNN neural network
easyExcel
HTB-Devel
Gbase 8C system table PG_ conversion
UDP receive queue and multiple initialization test