182

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.

Azhar
  • 20,500
  • 38
  • 146
  • 211
Hamid
  • 4,410
  • 10
  • 43
  • 72
  • 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).. thanks – Ewoks Feb 24 '12 at 10:16
  • @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. – Hamid Feb 27 '12 at 10:43
  • possible duplicate of [How to get a resource id with a known resource name?](http://stackoverflow.com/questions/3476430/how-to-get-a-resource-id-with-a-known-resource-name) – Jannie Theunissen Jun 11 '15 at 13:17

14 Answers14

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

Volo
  • 28,673
  • 12
  • 97
  • 125
Macarse
  • 91,829
  • 44
  • 175
  • 230
  • 9
    @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. – CommonsWare Dec 13 '10 at 11:32
  • 1
    @CommonsWare: That's right. I was checking how android implemented and it ends ups being a native call. http://gitorious.org/android-eeepc/base/blobs/3661101005c6527dfd384d0c88c4a3b68ee208af/core/java/android/content/res/Resources.java#line1346 => http://gitorious.org/android-eeepc/base/blobs/3661101005c6527dfd384d0c88c4a3b68ee208af/core/java/android/content/res/AssetManager.java#line609 – Macarse Dec 13 '10 at 11:50
  • 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"? – Hamid Dec 13 '10 at 11:51
  • @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. – Macarse Dec 13 '10 at 11:55
  • @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. – Hamid Dec 13 '10 at 12:21
  • @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? – EboMike Dec 13 '10 at 20:22
  • 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. – Hamid Dec 13 '10 at 20:32
  • 3
    I would use an integer array with the IDs instead. Using strings for IDs doesn't sound like the right approach. – EboMike Dec 13 '10 at 22:02
  • I accept this answer because of the solutions suggested in the comments by EboMike. Integer IDs was definately the way to go. – Hamid May 18 '11 at 12:55
  • 9
    Why the `context` parameter? – Rudey Sep 01 '13 at 10:33
  • 1
    Always return -1 for me. – Bagusflyer May 13 '15 at 09:32
  • 14
    Calling should be getId("icon", R.drawable.class); not getResId("icon", context, Drawable.class); – Smeet Jan 12 '16 at 10:58
  • How do I use this look up a string? Which class should I pass as the second parameter – Kaloyan Roussev Sep 07 '16 at 09:43
  • you should follow this https://stackoverflow.com/questions/3476430/how-to-get-a-resource-id-with-a-known-resource-name – Daniele Sep 11 '19 at 08:08
  • 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. – steve Dec 03 '21 at 09:10
  • 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")` – Volo Jul 27 '23 at 16:51
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

marca311
  • 13
  • 4
Azhar
  • 20,500
  • 38
  • 146
  • 211
  • 13
    What is the point of making a function that simply calls another one and "handles" a possible exception? Call getResources().getIdentifier() directly. – Ricardo Meneghin Filho Apr 22 '16 at 21:24
  • 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. – Shankari Jun 05 '21 at 15:09
  • Is there also the opposite? Meaning from `R.string.some_string` to "some_string" ? – android developer Sep 19 '21 at 10:46
  • Use of getIdentifier is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of code – Darksymphony Feb 01 '23 at 10:30
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);
Jonik
  • 80,077
  • 70
  • 264
  • 372
Daniel De León
  • 13,196
  • 5
  • 87
  • 72
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.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Martin Pearman
  • 592
  • 5
  • 5
  • 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); }` – Evilripper Apr 12 '16 at 12:33
  • also use of getIdentifier is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of code – Darksymphony Feb 01 '23 at 10:27
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);
}
Peter Knego
  • 79,991
  • 11
  • 123
  • 154
10

Simple method to get resource ID:

public int getDrawableName(Context ctx, String str){
    return ctx.getResources().getIdentifier(str,"drawable", ctx.getPackageName());
}
Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
Ivan Vovk
  • 929
  • 14
  • 28
  • 2
    Would be better if you just give some more information to your answer. – xMRi Oct 09 '17 at 14:15
  • Use of getIdentifier is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of code – Darksymphony Feb 01 '23 at 10:17
9

I did like this, it is working for me:

    imageView.setImageResource(context.getResources().
         getIdentifier("drawable/apple", null, context.getPackageName()));
Sarvar Nishonboyev
  • 12,262
  • 10
  • 69
  • 70
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.

EboMike
  • 76,846
  • 14
  • 164
  • 167
  • 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. – Steve Waring Aug 02 '14 at 07:35
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.

Steve Waring
  • 2,882
  • 2
  • 32
  • 37
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);
Leos Literak
  • 8,805
  • 19
  • 81
  • 156
ExploringAI
  • 451
  • 9
  • 12
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")
Krešimir Prcela
  • 4,257
  • 33
  • 46
Arsenius
  • 4,972
  • 4
  • 26
  • 39
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);  
Gene
  • 10,819
  • 1
  • 66
  • 58
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.

Daniele D.
  • 2,624
  • 3
  • 36
  • 42
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;
    }
}
bitvale
  • 1,959
  • 1
  • 20
  • 27