1. 概述
这节课我们来分析下Google是如何进行 资源加载的,比如我们直接在布局文件中写一个 ImageView,然后直接用 android:src="@mipmap/ic_launcher" 就能引入一张图片,到底是为什么,那么接下来我们就来看下, 系统到底是如何加载资源的,下边我们就以 ImageView里边的 src 为例,来进行源码分析,或者文字的textColor都是一样的,都是根据下边源码分析的。
2. 源码分析流程如下
2.1>:直接点击ImageView,进入源码,然后看下ImageView的第三个构造方法:
public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initImageView();
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
final Drawable d = a.getDrawable(R.styleable.ImageView_src);
if (d != null) {
setImageDrawable(d);
}
mBaselineAlignBottom = a.getBoolean(R.styleable.ImageView_baselineAlignBottom, false);
mBaseline = a.getDimensionPixelSize(R.styleable.ImageView_baseline, -1);
setAdjustViewBounds(a.getBoolean(R.styleable.ImageView_adjustViewBounds, false));
setMaxWidth(a.getDimensionPixelSize(R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
setMaxHeight(a.getDimensionPixelSize(R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
final int index = a.getInt(R.styleable.ImageView_scaleType, -1);
}
从上边我们看到,解析ImageView的 src
final Drawable d = a.getDrawable(R.styleable.ImageView_src);
然后点击 getDrawable进去,进入 TypedArray源码 中,看到 getDrawable()方法如下:
@Nullable
public Drawable getDrawable(@StyleableRes int index) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
}
return mResources.loadDrawable(value, value.resourceId, mTheme);
}
return null;
}
可以看到,不管是解析图片资源ImageView、还是文字的 textColor资源,其实最终都是调用的
mResources.loadDrawable(value, value.resourceId, mTheme);
而这个 mResources 其实就是 Resource,也就是说资源加载都是通过 Resource对象去读取的。既然资源的加载都是通过 Resource类加载的,那么如果我想获取另外一个apk中的资源,是不是可以自己实例化一个Resource。
只要清楚是怎么去实例化 Rescource就好,也就是说是如何 new Rescource对象,下边可以看到源码中它也是直接 new Rescource对象的
r = new Resources(assets, dm, config, compatInfo);
// 这个是 点击Resources进去的 ,它的构造方法,参数1 assets表示 AssetManager资源管理
Resources(AssetManager assets, DisplayMetrics metrics, Configuration config)
在这里我们只需要搞清楚 AssetManager资源管理是怎么实例化的就ok,
@VisibleForTesting
protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
AssetManager assets = new AssetManager();
if (key.mResDir != null) {
if (assets.addAssetPath(key.mResDir) == 0) {
Log.e(TAG, "failed to add asset path " + key.mResDir);
return null;
}
}
}
return assets;
}
通过下边的方法可以知道,它是直接 new AssetManager的,同时也调用了
assets.addAssetPath(key.mResDir)方法,里边的 mResDir 就是 apk的目录
/**
* Add an additional set of assets to the asset manager. This can be
* either a directory or ZIP file. Not for use by applications. Returns
* the cookie of the added asset, or 0 on failure.
* {@hide}
*/
public final int addAssetPath(String path) {
synchronized (this) {
int res = addAssetPathNative(path, appAsLib);
makeStringBlocks(mStringBlocks);
return res;
}
}
通过以上分析,总结资源加载
所有的资源加载是通过 Resource ->
而Rescource是直接 new = new Resources(assets, dm, config, compatInfo);对象,参数assets是非常重要的 ->
AssetsManager,这个其实是 Resource的核心的实例 ->
其实最终获取资源是通过 AssetsManager获取的;
AssetsManager实例化如下,并且调用 addAssetPath(key.mResDir)方法,注意下边的key.mResDir可以是一个 ZIP路径,其实就是 apk的目录
AssetManager assets = new AssetManager();
assets.addAssetPath(key.mResDir)
以上就是 资源加载的源码分析,注意其实 .apk也是 .zip,都是一样的。