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.
     * 
     * 

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值一样

Android动态获取资源ID之getIdentifier()_第1张图片

布局文件R.layout.activity_main ,从AS工程R.class可以看到int类型的索引值2130903040

Android动态获取资源ID之getIdentifier()_第2张图片
动态获取的R.layout.activity_main 同样为2130903040

Android动态获取资源ID之getIdentifier()_第3张图片

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;
    }

}

结语

 记录下自己的学习和工作经验,分享给有需要的人。如果有那里写的不对或者不理解,欢迎大家的指正。

你可能感兴趣的:(Android动态获取资源ID之getIdentifier())