通过 AssestManager 加载外部皮肤包
2019-08-20 本文已影响0人
石器时代小古董
一、Android APK 中的资源文件
在将程序打包成 APK 后,资源文件会单独打包成 resources.arsc 文件。它通过包名进行管理,通过ID,Name的方式通过 Resources 类进行加载。
二、加载外部的资源包
资源包实际上是一个 APK,它可以被 AssestManager进行加载,并通过 Resources 类加载其中的资源。
三、资源文件如果被Resources类引用
资源文件是通过 ID 被 Resources 引用到的。所以如果皮肤包中的资源和我们apk中原始的资源 ID 是一致的话,我们可以用通过这个ID在皮肤包的Resources中找到对应的资源,加载这个资源实现皮肤的替换
四、加载外部资源
1.外部资源可以通过AssestManager进行加载,所以首先需要创建一个AssestManager
注意这里不能使用Application.getAssest(),这种方式获得AssetManager会少初始化很多东西
AssetManager assetManager = AssetManager.class.newInstance();
2.AssestManager加载皮肤包
AssestManager通过addAssetPath的函数加载资源包,但这个函数本身是隐藏的,需要通过反射的方式加载
Method addAssetPath = assetManager.getClass().getDeclaredMethod(ADD_ASSET_PATH, String.class);
// 设置私有方法可访问
addAssetPath.setAccessible(true);
// 执行addAssetPath方法
addAssetPath.invoke(assetManager, skinPath);
3.读取皮肤包中的资源
有了AssestManager后,就可以获取到 Resources 类了
这里通过了apk已经准备好的资源类获取到了DsplayMetrics,Configuration 参数
this.application = application;
appResources = application.getResources();
skinResources = new Resources(assetManager,
appResources.getDisplayMetrics(), appResources.getConfiguration());
4.通过ID映射实际的资源
需要找到皮肤包中对应的资源的 ID
private int getSkinResourceIds(int resourceId) {
if (isDefaultSkin) return resourceId;
String resourceName = appResources.getResourceEntryName(resourceId);
String resourceType = appResources.getResourceTypeName(resourceId);
// 动态获取皮肤包内的指定资源ID
// getResources().getIdentifier(“netease_bg”, “drawable”, “com.netease.skin.packages”);
int skinResourceId = skinResources.getIdentifier(resourceName, resourceType, skinPackageName);
isDefaultSkin = skinResourceId == 0;
return skinResourceId == 0 ? resourceId : skinResourceId;
}
5.加载皮肤包的资源
有了 ID 就可以加载皮肤包中的资源了,在需要换肤的时候通过这些通过使用皮肤包的 Resources 类加载其中的资源实现换肤
public int getColor(int resourceId) {
int ids = getSkinResourceIds(resourceId);
return isDefaultSkin ? appResources.getColor(ids) : skinResources.getColor(ids);
}
public ColorStateList getColorStateList(int resourceId) {
int ids = getSkinResourceIds(resourceId);
return isDefaultSkin ? appResources.getColorStateList(ids) : skinResources.getColorStateList(ids);
}
// mipmap和drawable统一用法(待测)
public Drawable getDrawableOrMipMap(int resourceId) {
int ids = getSkinResourceIds(resourceId);
return isDefaultSkin ? appResources.getDrawable(ids) : skinResources.getDrawable(ids);
}
public String getString(int resourceId) {
int ids = getSkinResourceIds(resourceId);
return isDefaultSkin ? appResources.getString(ids) : skinResources.getString(ids);
}