Android - getResources().getIdentifier替代方案

6
在Android中,我正在循环遍历数据库并分配文本和图像:
Cursor res = myDb.getAllData();

while (res.moveToNext()) {
    Actors actor = new Actors();
    actor.setName(res.getString(1));

    String th =  res.getString(11);
    Integer thumb = this.getResources().getIdentifier(th, "drawable", "mypackage");

    actor.setThumb(R.drawable.th);
}

然而Lint建议不要使用getIdentifier - 不推荐使用此函数,因为资源反射使得执行构建优化和代码的编译时验证更加困难。

在数据库列中,我只有图像名称(字符串)。我该如何替换getIdentifier?

即使我将DB列直接更改为,它仍然是一个字符串,但对于setThumb我需要一个可绘制对象。


有多少张图片?您可以使用switch语句,或者构建和缓存一个字符串到标识符值的Map<String, Integer>并使用它。 - CommonsWare
在数据库列中,整数代表什么?我需要图片名称。即使您在数据库中有一个整数,也不能在代码中动态使用它作为drawable,因为drawable是drawable,除非您将drawable ID存储在数据库中,但我不知道所有200个图像的ID,并且未来还会有更多。 - Darksymphony
你可以将可绘制对象存储到XML数组或Java数组中(与循环顺序相同);然后将该整数(每个可绘制对象的顺序)存储到数据库中,而不是字符串。 - Zain
嗯,也许不是一个坏主意,但如果我将那些可绘制对象存储在另一个地方,我为什么要使用数据库呢?但如果没有其他办法,至少似乎是一个可行的解决方法。如果您能发布一个带有这样一个示例的答案,那就太好了,您确切地是如何想到它的。 - Darksymphony
1
刚看到你通过反射找到了解决方案,太棒了!我想不需要回答了;如果你还需要,请给我留言。 - Zain
显示剩余2条评论
5个回答

1
最好的方法是使用类似这个例子中的mapOf列表。
val iconResourceMap = mapOf(
        "icon_1" to R.drawable.icon_1,
        "icon_2" to R.drawable.icon_2,
        // Add mappings for all the icons you have
    )

    for (i in 0 until data.length()) {
        val iconName = "icon_${i + 1}"
        val iconResId = iconResourceMap[iconName] ?: 0
}

愉快编码!


0

好的,所以我找到的唯一解决方案在这里https://dev59.com/Wm855IYBdhLWcg3wSiQ7#4428288

public static int getResId(String resName, Class<?> c) {

        try {
            Field idField = c.getDeclaredField(resName);
            return idField.getInt(idField);
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        } 
    }

然后只需调用:

int resID = getResId("icon", R.drawable.class);

这个方法非常有效,但是一些用户报告说,在从Play商店安装应用程序后(不是我的应用程序,而是任何实现了此方法并启用了proguard的应用程序),过一段时间后它将开始抛出NoSuchFieldException,因为更多的资源被映射到同一个类/字段。

这可能是由proguard引起的,但不确定。解决方案是将旧的方式getResources().getIdentifier放到代码的异常部分。


6
但是这种方法使用了直接反射,所以它比你原来的解决方案更加hacky。 - bongo
好的,我没有找到其他的解决方案,一些博客发布说这比使用getIdentifier快了5倍。我不知道还有什么其他的解决方案。 - Darksymphony
1
请问您能分享一下博客文章链接吗?在那里他们声称这种方法快了5倍?谢谢。 - Lino
例如在这里http://daniel-codes.blogspot.com/2009/12/dynamically-retrieving-resources-in.html。 - Darksymphony
@Darksymphony,这种方法可能会更快,但不可靠且容易出错,请不要使用它!例如,如果你有<string name="string.name">,实际的字段名将是string_name。但更大的问题是,如果启用了资源/代码缩减(Google鼓励启用),它将在生产环境(发布版本)中失败。与此方法相反,你应该在代码中将字符串名称映射为整数ID,或者如果绝对必要,可以使用Resources.getIdentifier结合@SuppressLint("DiscouragedApi") - Volo

0
你可以尝试以下方法:
  • 将你的资源按照以下方式进行重命名: ressourceName00 ressourceName01 ressourceName02 .... 以此类推,

然后使用下面的方法:

for (int i = 0; i < RessourceQtt; i++) {
        Uri path1 = Uri.parse("android.resource://yourPackage Directories/drawable/ressourceName0" + i);

        list.add(new CarouselItem(String.valueOf(path1)));
    }

0

你可以��试我的代码三种方式

// Show message and quit
    Application app = cordova.getActivity().getApplication();
    String package_name = app.getPackageName();
    Resources resources = app.getResources();
    String message = resources.getString(resources.getIdentifier("message", "string", package_name));
    String label = resources.getString(resources.getIdentifier("label", "string", package_name));
    this.alert(message, label);

设置图标如下

private int getIconResId() {
Context context = getApplicationContext();
Resources res = context.getResources();
String pkgName = context.getPackageName();
int resId;
resId = res.getIdentifier("icon", "drawable", pkgName);
return resId;

}

这也是

//set icon image
final String prefix = "ic_";
String icon_id = prefix + cursor.getString(cursor.getColumnIndex(WeatherEntry.COLUMN_ICON));
Resources res = mContext.getResources();
int resourceId = res.getIdentifier(icon_id, "drawable", mContext.getPackageName());
viewHolder.imgIcon.setImageResource(resourceId);

希望这段代码对您有所帮助。

public static int getIcId(String resN, Class<?> c) {
try {
    Field idF = c.getDeclaredField(resN);
    return idF.getInt(idF);
} catch (Exception e) {
    throw new RuntimeException("No resource ID found for: "
            + resN+ " / " + c, e);
}}

0
在 Kotlin 中,由于 getIdentifierTyped Array
这段代码可以这样写:
resources.getIdentifier("l$i", "drawable", packageName)

必须执行两个步骤:

1- 在 res/values/arrays.xml 中创建一个数组列表

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <array name="icons">
        <item>@drawable/home</item>
        <item>@drawable/settings</item>
        <item>@drawable/logout</item>
    </array>
 
</resources>

2- 在Activity中调用

val icons: TypedArray = resources.obtainTypedArray(R.array.icons)
val drawable: Drawable = icons.getDrawable(0)

要点:

I)如果您想将ID作为Int调用,请使用以下方式:

icons.getResourceId(i,0) //i is a counter

II) 如果您在使用Recycle View中使用它,则必须添加

 icons.recycle()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接