Android获取drawable下所有资源文件id

本文详细介绍了如何通过反射获取drawable目录下所有图片文件的名称,并获取每个文件对应的资源ID,提供了完整的代码实现步骤。
        //获取drawable文件名列表,不包含扩展名
        Field[] fields = R.drawable.class.getDeclaredFields();
        for(Field field:fields){
        	/*获取文件名对应的系统生成的id
        	需指定包路径 getClass().getPackage().getName()
        	指定资源类型drawable*/
        	int resID = getResources().getIdentifier(field.getName(), 
        			"drawable", getClass().getPackage().getName()); 
        	System.out.println("fileName = " + field.getName() 
        			+ "    resId = " + resID);
        }
    }

<think>Androiddrawable资源ID并非固定不变,它会随着编译过程动态生成。但是,在运行时我们可以通过资源ID稳定地访问资源。 在编译时,每个资源文件都会在R类中生成一个唯一的整型ID(在R.drawable类中)。这个ID在每次编译时可能会改变(如果资源发生变化,比如增删资源),但在同一个编译版本中是固定的。 因此,在代码中引用资源ID时(如R.drawable.my_image),在应用运行期间,这些ID是固定不变的。但是,请注意以下几点: 1. **编译时生成**:每次重新编译项目,资源ID可能会重新分配(如果资源有变化)。但在同一个APK版本中,这些ID是固定的。 2. **动态获取**:可以通过资源名称动态获取资源ID,使用`Resources.getIdentifier()`方法,但这种方式效率较低,不推荐频繁使用。 3. **资源ID优化**:在构建过程中,Android构建工具会优化资源ID,并且它们最终会被打包成二进制格式,在运行时通过资源表访问。 ### 代码示例:访问drawable资源 #### 1. 静态引用(推荐) 在代码中直接使用资源ID,这是最常见的做法: ```java // 设置ImageView的图片资源 ImageView imageView = findViewById(R.id.imageView); imageView.setImageResource(R.drawable.my_image); ``` #### 2. 动态获取(不推荐,除非必要) ```java // 通过资源名称获取ID Resources res = getResources(); int drawableId = res.getIdentifier("my_image", "drawable", getPackageName()); if (drawableId != 0) { imageView.setImageResource(drawableId); } else { Log.e("Resource", "Drawable not found!"); } ``` ### 注意事项: - 资源ID在同一个应用版本中是固定的,但不同版本可能不同。 - 资源ID在编译后会被优化成非连续的整型值(不再是R.java中看到的常量值),但这不影响我们使用R.drawable.xxx来访问。 - 在库模块中,资源ID不是final的(除非使用Android Gradle Plugin 3.6.0或更高版本并启用非传递性R类),因此不能在switch语句中使用(可以使用if-else if)。 ### 资源ID的内部表示 在打包过程中,资源ID被分成三个部分: - Package ID(8位):表示资源所属的包,应用资源通常是0x7F,库资源是0x01、0x02等。 - Type ID(8位):表示资源类型(如drawable, layout等)。 - Entry ID(16位):资源的特定项。 例如,0x7f020001 表示: - Package ID: 7f(应用自身资源) - Type ID: 02(表示drawable类型) - Entry ID: 0001(该类型下的第一个资源) ### 资源ID的稳定性 在以下情况下,资源ID可能会改变: - 添加或删除资源:导致同一类型下的资源顺序变化,从而改变Entry ID。 - 更新库模块:库模块的资源ID可能会改变。 - 启用或禁用资源合并:不同的构建配置可能导致资源ID变化。 ### 结论 在同一个APK中,资源ID是固定不变的。因此,可以安全地在代码中保存资源ID(例如在SharedPreferences中保存资源ID)?但需要注意的是,后续版本如果资源发生变化,保存的资源ID可能不再有效。因此,建议保存资源名称而不是资源ID。 ### 最佳实践 如果需要持久化引用资源,应该保存资源名称(字符串),然后在需要时通过`Resources.getIdentifier()`获取ID。但这种方法效率较低,因此通常仅在必要时使用。 ### 示例:保存和恢复资源名称 ```java // 保存资源名称 String resName = getResources().getResourceEntryName(R.drawable.my_image); SharedPreferences.Editor editor = getSharedPreferences("prefs", MODE_PRIVATE).edit(); editor.putString("image_res_name", resName); editor.apply(); // 恢复 String savedResName = getSharedPreferences("prefs", MODE_PRIVATE).getString("image_res_name", ""); if (!savedResName.isEmpty()) { int resId = getResources().getIdentifier(savedResName, "drawable", getPackageName()); if (resId != 0) { imageView.setImageResource(resId); } } ``` §§相关问题§§: 1. 如何在Android中动态切换应用主题? 2. 如何在不同分辨率设备上正确显示图片资源? 3. Android的资源管理机制是怎样的? 4. 如何避免drawable资源导致的OOM(内存溢出)? </think>### Android Drawable 资源 ID 解析 在 Android 开发中,drawable 目录下的资源图片 ID **不是固定的**,但它们在编译后生成的 R 文件中会被赋予**固定不变的整型值**(在同一个应用版本中)。以下是详细解释和解决方案: #### 核心概念解析 1. **资源 ID 生成机制**: - 每个资源文件在编译时都会在 `R.java` 中生成唯一的静态整型 ID - ID 值格式:`0x7f[类型][索引]`(应用资源)或 `0x01[类型][索引]`(库资源) - 示例:`R.drawable.ic_logo` → `0x7f020001` 2. **"固定"的误解**: - ✅ **同一应用版本**:ID 固定不变 - ❌ **跨版本/设备**:ID 可能变化(资源增减/构建工具更新) - ❌ **动态获取**:`getIdentifier()` 返回值可能因设备而异 #### 最佳实践代码示例 ##### 1. 安全使用资源 ID(Kotlin) ```kotlin // 正确用法:直接引用编译时生成的ID imageView.setImageResource(R.drawable.ic_logo) // 错误用法:动态获取ID(不保证稳定性) val dynamicId = resources.getIdentifier("ic_logo", "drawable", packageName) imageView.setImageResource(dynamicId) // 可能在不同设备上失效 ``` ##### 2. 资源 ID 处理技巧 ```java // 检查资源是否存在(Android 5.0+) public boolean isDrawableExist(@DrawableRes int resId) { try { return getResources().getDrawable(resId, null) != null; } catch (Resources.NotFoundException e) { return false; } } // 安全设置图片 public void safeSetImage(ImageView imageView, @DrawableRes int resId) { if (isDrawableExist(resId)) { imageView.setImageResource(resId); } else { imageView.setImageResource(R.drawable.fallback_icon); Log.w("Resource", "Drawable not found: " + resId); } } ``` ##### 3. 处理不同分辨率资源 ```xml <!-- 分辨率限定符确保正确选择资源 --> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" app:srcCompat="@drawable/ic_logo" /> <!-- 使用AppCompat支持矢量图 --> <!-- drawable目录结构 --> res/ ├── drawable/ # 默认(mdpi) ├── drawable-hdpi/ # 高分辨率 ├── drawable-xhdpi/ # 超高分辨率 └── drawable-xxhdpi/ # 超超高分辨率 ``` #### 资源 ID 生命周期详解 | 阶段 | ID 状态 | 开发者注意事项 | |--------------------|----------------------------|---------------------------| | 源代码阶段 | 符号引用 (R.drawable.foo) | 使用符号名称,无需关心具体值 | | 编译时 (AAPT2) | 分配固定整型值 | 资源变化会导致ID重新分配 | | 打包后 (APK) | 资源表固定映射 | 同一APK中ID永久固定 | | 运行时 | 通过 Resources 对象访问 | 使用`@DrawableRes`注解保证安全 | #### 特殊情况处理 ##### 1. 动态切换主题资源 ```java // 正确方式:使用主题属性引用 <ImageView android:src="?attr/iconHome" /> // styles.xml <style name="AppTheme"> <item name="iconHome">@drawable/ic_home_light</item> </style> // 代码中切换 imageView.setImageDrawable( ContextCompat.getDrawable(context, R.attr.iconHome) ); ``` ##### 2. 跨模块资源访问 ```groovy // build.gradle (依赖库模块) dependencies { implementation project(':mylibrary') } ``` ```java // 访问库模块资源(ID稳定但不同模块) imageView.setImageResource(com.example.mylibrary.R.drawable.lib_icon); ``` ##### 3. 矢量图兼容方案 ```groovy // build.gradle android { defaultConfig { vectorDrawables.useSupportLibrary = true } } ``` ```xml <!-- 使用AppCompat兼容旧设备 --> <androidx.appcompat.widget.AppCompatImageView app:srcCompat="@drawable/ic_vector_logo" /> ``` #### 资源保护机制 1. **Proguard 保留规则**: ```proguard -keepclassmembers class **.R$* { public static <fields>; } ``` 2. **资源压缩配置**: ```xml <!-- res/raw/keep.xml --> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@drawable/important_*" /> ``` 3. **资源验证工具**: ```bash # 检查资源稳定性 ./gradlew :app:lintDebug --check 'UnstableResourceId' ``` #### 资源 ID 问题排查指南 1. **崩溃:`Resources$NotFoundException`** ```java try { drawable = ContextCompat.getDrawable(context, R.drawable.missing); } catch (Resources.NotFoundException e) { // 处理资源丢失 FirebaseCrashlytics.log("Drawable missing: " + e.getMessage()); } ``` 2. **资源覆盖检测**: ```bash # 查看最终资源分配 ./gradlew :app:processDebugResources --info ``` 3. **资源冲突解决**: ```xml <!-- 使用别名解决同名资源冲突 --> <drawable name="ic_logo">@drawable/module_specific_logo</drawable> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值