Android动态获取资源ID之getIdentifier()
前言
再说getIdentifier()前,科普下什么是SDK:SDK(Software Development Kit)是软件开发工具包的意思,一般我们将一部分功能单独封装成一个库文件进行开发和维护,然后将库文件提供给第三方使用。
1.应用场景描述
SDK都是基于AS进行功能开发的 ,因为要提供给别人使用,而AS作为库文件的最终产物就是.aar文件。SDK开发精髓就是麻烦自己方便别人。既然提供了AS库支持自然也要提供EC库的支持 ,但是EC它不支持aar文件,怎么办嘞,aar文件也是压缩包,将aar解压出来,把里面的classes.jar拷贝出来重命名,然后在Eclipse中依赖这个jar包,同时,SDK的资源文件、Assets相关也需要拷贝到Eclipse项目中。
1.1异常原因分析
将AS库放到EC工程里发生崩溃Caused by: android.content.res.Resources$NotFoundException:
经过分析找到了问题原因所在:举个例子,sdk用到 setContentView(R.layout.activity_main)这种方式展示布局, 当我们把资源文件拷贝到Eclipse,再编译apk的时候,资源文件会对应一个新的资源id,而aar中classes.jar里引用R中id的是不变的 也就是说在.aar文件中setContentView(2130903040),
到了EC中重新编译后aapt会重新赋予activity_main一个新的值,自然报找不到资源ID 的异常了 。要解决这个问题需要SDK动态的获取资源ID ,不能直接写死,查找过一些资料发现,谷歌提供了相关的API,可以通过资源名称获取资源id
/**
* Return a resource identifier for the given resource name. A fully
* qualified resource name is of the form "package:type/entry". The first
* two components (package and type) are optional if defType and
* defPackage, respectively, are specified here.
*
* <p>Note: use of this function is discouraged. It is much more
* efficient to retrieve resources by identifier than by name.
*
* @param name The name of the desired resource.
* @param defType Optional default resource type to find, if "type/" is
* not included in the name. Can be null to require an
* explicit type.
* @param defPackage Optional default package to find, if "package:" is
* not included in the name. Can be null to require an
* explicit package.
*
* @return int The associated resource identifier. Returns 0 if no such
* resource was found. (0 is not a valid resource ID.)
*/
public int getIdentifier(String name, String defType, String defPackage) {
return mResourcesImpl.getIdentifier(name, defType, defPackage);
}
API格式getIdentifier(“资源ID名称”,“资源类型”,“应用包名”)
getIdentifier(“activity_main”,“layout”,“com.demo.xxxx”)
2.Demo示例
通过上面提供的官方API ,尝试写一个DEMO 验证下
在Activity中 调用封装好的getIdentifier(),看下动态获取的ID是否和R.layout.activity_main值一样
布局文件R.layout.activity_main ,从AS工程R.class可以看到int类型的索引值2130903040
动态获取的R.layout.activity_main 同样为2130903040
2.1结论
ResourceUtils.getLayoutId(context,“activity_main”))等效于R.layout.activity_main
SDK是给第三方使用的,避免使用R.layout.main方式引用资源。而且在游戏SDK圈中,涉及到编译和反编译等技术多资源合并去重。
在三方使用的时候资源id经常会发生改变,如果还用R.layout.main方式会造成第三方接入难度 等很多不确定因素。
3. 工具类封装
import android.content.Context;
import java.lang.reflect.Field;
/**
* @author sjr
* Date 2020/7/16
*/
public class ResourceUtils {
public static int getAnimId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "anim", context.getPackageName());
}
public static int getAnimatorId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "animator", context.getPackageName());
}
public static int getAttrId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "attr", context.getPackageName());
}
public static int getBoolId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "bool", context.getPackageName());
}
public static int getColorId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "color", context.getPackageName());
}
public static int getDimenId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "dimen", context.getPackageName());
}
public static int getDrawableId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "drawable", context.getPackageName());
}
public static int getId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "id", context.getPackageName());
}
public static int getIntegerId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "integer", context.getPackageName());
}
public static int getInterpolatorId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "interpolator", context.getPackageName());
}
public static int getLayoutId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "layout", context.getPackageName());
}
public static int getPluralsId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "plurals", context.getPackageName());
}
public static int getStringId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "string", context.getPackageName());
}
public static int getStyleId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "style", context.getPackageName());
}
public static int getStyleableId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "styleable", context.getPackageName());
}
public static int getXmlId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "xml", context.getPackageName());
}
public static int getMipmapId(Context context, String defType) {
return context.getResources().getIdentifier(defType, "mipmap", context.getPackageName());
}
/**
* 通过反射来读取int[]类型资源Id
* @param context
* @param name
* @return
*/
public static final int[] getResourceDeclareStyleableIntArray(Context context, String name) {
try {
Field[] fields2 = Class.forName(context.getPackageName() + ".R$styleable" ).getFields();
for (Field f : fields2 ){
if (f.getName().equals(name)){
int[] ret = (int[])f.get(null);
return ret;
}
}
}
catch (Throwable t){
}
return null;
}
}
结语
记录下自己的学习和工作经验,分享给有需要的人。如果有那里写的不对或者不理解,欢迎大家的指正。
本文地址:https://blog.csdn.net/baidu_31156101/article/details/107402888