Android, getting resource ID from string?
Asked Answered
K

15

184

I need to pass a resource ID to a method in one of my classes. It needs to use both the id that the reference points to and also it needs the string. How should I best achieve this?

For example:

R.drawable.icon

I need to get the integer ID of this, but I also need access to the string "icon".

It would be preferable if all I had to pass to the method is the "icon" string.

Kessiah answered 13/12, 2010 at 9:55 Comment(3)
is it possible in similar way to getId of files saved to internal storage? I have problem cause I should supply array of ids instead of locations to my gallery (thought it's adapter).. thanksOnrush
@Ewoks: They don't have IDs on internal storage. They're just images, if anything you need to load them into a bunch of Image objects and pass those, you might want to start a new question though.Kessiah
possible duplicate of How to get a resource id with a known resource name?Pendulous
I
198

@EboMike: I didn't know that Resources.getIdentifier() existed.

In my projects I used the following code to do that:

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

It would be used like this for getting the value of R.drawable.icon resource integer value

int resID = getResId("icon", R.drawable.class); // or other resource class

I just found a blog post saying that Resources.getIdentifier() is slower than using reflection like I did. Check it out.

WARNING: This solution will fail in the release build if code/resource shrinking is enabled as suggested by Google: https://developer.android.com/build/shrink-code
Also, it might fail for some other cases, e.g. when you have <string name="string.name">…</string> the actual field name will be string_name and not the string.name

Immediate answered 13/12, 2010 at 11:21 Comment(16)
@Macarse: Presently, getIdentifier() has to do two reflection lookups. In your example above, getIdentifier() would use reflection to get Drawable.class, then another reflection lookup to get the resource ID. That would account for the speed difference. That being said, neither are especially quick and therefore really need to be cached (particularly if used in a loop, or for rows in a ListView). And the reflection approach's big problem is that it makes assumptions about the internals of Android that might change in some future release.Glaucescent
@CommonsWare: That's right. I was checking how android implemented and it ends ups being a native call. gitorious.org/android-eeepc/base/blobs/… => gitorious.org/android-eeepc/base/blobs/…Immediate
Sorry guys, I still don't see an acceptable answer. I want to minimize parameters not increase them. how about if I pass the resource Id (R.drawable.icon) as an integer, can I then use the id to get the resource name and strip just the part I need to get "icon"?Kessiah
@Hamid: If you can pass R.drawable.icon to your method you can just do it like you said: methodName(int R.drawable.icon, "icon");. I don't know why you want to do that, thought.Immediate
@Marcarse: I just want to pass the one, myMethod(int R.drawable.icon) and the method will use the int as the resource to load, and find "icon" as the string to identify it.Kessiah
@Hamid: Well, maybe you should tell us exactly what you want? You wanted to convert a string to an ID, you got two solutions for that. Tell us what you're trying to do, what data you have and what you don't have, and we can adjust the answers. If you have the ID as an int, then why do you need to convert a string to an int?Impatient
I'm loading some images, I need a string to identify each image, and I need the id (int) that will let me get the image from the resources. I would like the identifying string to be the filename (minus extension) that is at the end of the R.drawable.filename (int) that I can pass to the method.Kessiah
I would use an integer array with the IDs instead. Using strings for IDs doesn't sound like the right approach.Impatient
I accept this answer because of the solutions suggested in the comments by EboMike. Integer IDs was definately the way to go.Kessiah
Why the context parameter?Juetta
Always return -1 for me.Dina
Calling should be getId("icon", R.drawable.class); not getResId("icon", context, Drawable.class);Cumin
How do I use this look up a string? Which class should I pass as the second parameterAthome
you should follow this #3476930Retortion
to help others: if this flexible solution works for a while but it starts to throw NoSuchFieldException, it can be caused by proguard obfuscator: the class in question is being obfuscated. (more resources are mapped to the same class/field). In my case the error happend only when installed from the play store (aab). Solution: in the catch try to get it by Resources.getIdentifier() or disable proguard.Mneme
DON'T use this! This solution might look neat, but it will come back to bite you. As mentioned by CommonsWare "the reflection big problem is that it makes assumptions about the internals of Android that might change in some future release". And if you check SO comments that's already happened to quite a few people who discovered the method above fails in production, if minification is enabled. One should either map string names to int ids in the code, or if absolutely needed use the Resources.getIdentifier provided by the Android SDK combined with the @SuppressLint("DiscouragedApi")Bradstreet
R
98

You can use this function to get resource ID.

public static int getResourceId(String pVariableName, String pResourcename, String pPackageName) 
{
    try {
        return getResources().getIdentifier(pVariableName, pResourcename, pPackageName);
    } catch (Exception e) {
        e.printStackTrace();
        return -1;
    } 
}

So if you want to get for drawable call function like this

getResourceId("myIcon", "drawable", getPackageName());

and for string you can call it like this

getResourceId("myAppName", "string", getPackageName());

Read this

Reparative answered 30/9, 2013 at 11:48 Comment(4)
What is the point of making a function that simply calls another one and "handles" a possible exception? Call getResources().getIdentifier() directly.Etch
Upvoted for clarifying how to pass in the type to get different kinds or resources. The android dev documentation does not have details and "id" from a prior answer does not work for strings.Bona
Is there also the opposite? Meaning from R.string.some_string to "some_string" ?Tiliaceous
Use of getIdentifier is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of codeNolte
H
42

This is based on @Macarse answer.

Use this to get the resources Id in a more faster and code friendly way.

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

Example:

getId("icon", R.drawable.class);
Haukom answered 12/7, 2013 at 19:12 Comment(0)
S
29

How to get an application resource id from the resource name is quite a common and well answered question.

How to get a native Android resource id from the resource name is less well answered. Here's my solution to get an Android drawable resource by resource name:

public static Drawable getAndroidDrawable(String pDrawableName){
    int resourceId=Resources.getSystem().getIdentifier(pDrawableName, "drawable", "android");
    if(resourceId==0){
        return null;
    } else {
        return Resources.getSystem().getDrawable(resourceId);
    }
}

The method can be modified to access other types of resources.

Sidekick answered 12/4, 2012 at 3:10 Comment(2)
now .getResources().getDrawable is deprecated if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){ return mContext.getDrawable(resourceId); } else { return mContext.getResources().getDrawable(resourceId); }Tomlinson
also use of getIdentifier is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of codeNolte
W
13

If you need to pair a string and an int, then how about a Map?

static Map<String, Integer> icons = new HashMap<String, Integer>();

static {
    icons.add("icon1", R.drawable.icon);
    icons.add("icon2", R.drawable.othericon);
    icons.add("someicon", R.drawable.whatever);
}
Whaling answered 14/5, 2011 at 21:8 Comment(0)
E
10

Simple method to get resource ID:

public int getDrawableName(Context ctx, String str){
    return ctx.getResources().getIdentifier(str,"drawable", ctx.getPackageName());
}
Endodontics answered 9/10, 2017 at 11:42 Comment(2)
Would be better if you just give some more information to your answer.Mihalco
Use of getIdentifier is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of codeNolte
J
9

I did like this, it is working for me:

    imageView.setImageResource(context.getResources().
         getIdentifier("drawable/apple", null, context.getPackageName()));
Jugoslavia answered 26/7, 2013 at 13:49 Comment(2)
Thanks. Works as expected. I used the following: view.context.resources.getIdentifier("drawable/item_car_$position", null, context.packageName).Moulton
Use of getIdentifier is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of codeNolte
I
8

You can use Resources.getIdentifier(), although you need to use the format for your string as you use it in your XML files, i.e. package:drawable/icon.

Impatient answered 13/12, 2010 at 9:58 Comment(1)
My answer below is the reverse of this. Pass in the resource id, and then use getResourceEntryName(id) to find the string name. No messing to find "icon" from the longer text.Judgeship
J
7

Since you said you only wanted to pass one parameter and it did not seem to matter which, you could pass the resource identifier in and then find out the string name for it, thus:

String name = getResources().getResourceEntryName(id);

This might be the most efficient way of obtaining both values. You don't have to mess around finding just the "icon" part from a longer string.

Judgeship answered 2/8, 2014 at 7:32 Comment(0)
B
7

A simple way to getting resource ID from string. Here resourceName is the name of resource ImageView in drawable folder which is included in XML file as well.

int resID = getResources().getIdentifier(resourceName, "id", getPackageName());
ImageView im = (ImageView) findViewById(resID);
Context context = im.getContext();
int id = context.getResources().getIdentifier(resourceName, "drawable",
context.getPackageName());
im.setImageResource(id);
Burra answered 27/4, 2015 at 17:48 Comment(0)
D
6

The Kotlin approach

inline fun <reified T: Class<*>> T.getId(resourceName: String): Int {
            return try {
                val idField = getDeclaredField (resourceName)
                idField.getInt(idField)
            } catch (e:Exception) {
                e.printStackTrace()
                -1
            }
        }

Usage:

val resId = R.drawable::class.java.getId("icon")

Or:

val resId = R.id::class.java.getId("viewId")
Disquietude answered 2/4, 2019 at 2:8 Comment(2)
This works but what exactly is this doing? It has a very weird syntax. How is it performance wise?Laborsaving
This doesn't work with proguard/minify enabled.Louvenialouver
S
2

In your res/layout/my_image_layout.xml

<LinearLayout ...>
    <ImageView
        android:id="@+id/row_0_col_7"
      ...>
    </ImageView>
</LinearLayout>

To grab that ImageView by its @+id value, inside your java code do this:

String row = "0";
String column= "7";
String tileID = "row_" + (row) + "_col_" + (column);
ImageView image = (ImageView) activity.findViewById(activity.getResources()
                .getIdentifier(tileID, "id", activity.getPackageName()));

/*Bottom code changes that ImageView to a different image. "blank" (R.mipmap.blank) is the name of an image I have in my drawable folder. */
image.setImageResource(R.mipmap.blank);  
Syndic answered 3/4, 2018 at 5:25 Comment(0)
H
1

In MonoDroid / Xamarin.Android you can do:

 var resourceId = Resources.GetIdentifier("icon", "drawable", PackageName);

But since GetIdentifier it's not recommended in Android - you can use Reflection like this:

 var resourceId = (int)typeof(Resource.Drawable).GetField("icon").GetValue(null);

where I suggest to put a try/catch or verify the strings you are passing.

Hutchens answered 27/5, 2016 at 17:3 Comment(0)
A
1

For getting Drawable id from String resource name I am using this code:

private int getResId(String resName) {
    int defId = -1;
    try {
        Field f = R.drawable.class.getDeclaredField(resName);
        Field def = R.drawable.class.getDeclaredField("transparent_flag");
        defId = def.getInt(null);
        return f.getInt(null);
    } catch (NoSuchFieldException | IllegalAccessException e) {
        return defId;
    }
}
Antiicer answered 29/6, 2016 at 10:41 Comment(0)
L
0
    ImageId.substring(0, ImageId.length()-1);

    imageMessage = (ImageView) findViewById(R.id.imageMessage);

    int resID = getResources().getIdentifier(ImageId , "drawable", getPackageName());

    imageMessage.setImageResource(resID);

Dont forget to add substring

Largo answered 22/12, 2023 at 14:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.