Android批量引用资源文件

每次和同事吃饭的时候都会因为不知道吃什么而纠结好久,于是自己做了个小应用帮忙做选择。由于应用功能过于简单,想着加点好玩的东西上去,这时候,问题来了。

问题

应用通过随机一个position,让RecyclerView滑动到某个餐馆的位置,我要做的是在每个RecyclerView的item上依次加gif每一帧的图片,达到一个逐帧动画的效果。由于图片放在资源文件中(50张),这意味着我要手动添加50张图片文件资源的id于一个list,这也太麻烦了,我肯定不会干。

解决方案

等我累死累活50个添加完,我脑海中出现了某个想法:平时我们获取状态栏的高度是怎么获取的?

1
2
3
4
5
var result = 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}

这个getIdentifier函数就有说法了。

1
2
3
public int getIdentifier(String name, String defType, String defPackage) {
return mResourcesImpl.getIdentifier(name, defType, defPackage);
}

源码的解释是”Return a resource identifier for the given resource name”,大意是给一个资源的名字,会返回该资源的id。我们看一下入参:name(资源名称)、defType(资源类型)以及defPackage(包名)。
我们按此方法获取一下图片资源的id,看和R.xxx.xxx的方式获取的值是否一致。

1
2
3
Log.d(TAG, "通过R文件获取 -> ${R.drawable.man1}")
val resourceId = resources.getIdentifier("man1", "drawable", "com.yxd.thatdice")
Log.d(TAG, "通过getIdentifier获取 -> $resourceId")

image
诶,一致的,那就好办了,我们可以通过如下方式去获取一个资源文件的list(图片以man1.png,man2.png…的方式命名):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private const val DRAWABLE_TYPE = "drawable"
private const val PACKAGE_NAME = "com.yxd.thatdice"

fun getManList(context: Context): List<Int> {
val manList = ArrayList<Int>(50)
for (i in 1..50) {
manList.add(getResourceId(context, "man$i"))
}
return manList
}

fun getResourceId(context: Context, name: String): Int {
return context.resources.getIdentifier(name, DRAWABLE_TYPE, PACKAGE_NAME)
}

最后看一下效果,录制的时候有丢帧,就着看了:
image
至于效率问题,我也不敢说这种动态获取的方式一定会比直接从R文件读取低,或者低多少,这个还有待深入研究。至少从50张图片的量来看,可忽略不计。