当前位置:网站首页>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
边栏推荐
- Didi programmers are despised by relatives: an annual salary of 800000 is not as good as two teachers
- Awk from getting started to being buried (2) understand the built-in variables and the use of variables in awk
- [fluent] JSON model conversion (JSON serialization tool | JSON manual serialization | writing dart model classes according to JSON | online automatic conversion of dart classes according to JSON)
- Gbase 8C system table PG_ aggregate
- SQL statement
- tensor中的append应该如何实现
- GBase 8c系统表-pg_auth_members
- What does "where 1=1" mean
- HW initial preparation
- 【Flutter】shared_ Preferences local storage (introduction | install the shared_preferences plug-in | use the shared_preferences process)
猜你喜欢
awk从入门到入土(0)awk概述
What does "where 1=1" mean
Practice of traffic recording and playback in vivo
Thread safe singleton mode
where 1=1 是什么意思
Choose it when you decide
[shutter] banner carousel component (shutter_wiper plug-in | swiper component)
easyPOI
Create + register sub apps_ Define routes, global routes and sub routes
MATLAB小技巧(24)RBF,GRNN,PNN-神经网络
随机推荐
Tongda OA homepage portal workbench
[fluent] listview list (map method description of list set | vertical list | horizontal list | code example)
Error when installing MySQL in Linux: starting mysql The server quit without updating PID file ([FAILED]al/mysql/data/l.pid
Compréhension simple de SVG
Restcloud ETL cross database data aggregation operation
SQL statement
[tutorial] chrome turns off cross domain policies CORS and samesite, and brings cookies across domains
Add MDF database file to SQL Server database, and the error is reported
What does "where 1=1" mean
Awk from getting started to being buried (2) understand the built-in variables and the use of variables in awk
搭建私有云盘 cloudreve
Apple releases MacOS 11.6.4 update: mainly security fixes
HW-初始准备
Create + register sub apps_ Define routes, global routes and sub routes
Interview stereotyped version
Cvpr2022 remove rain and fog
【翻译】后台项目加入了CNCF孵化器
左值右指解释的比较好的
Thread safe singleton mode
random shuffle注意