1

If I have different resource names like elephant, tiger and cat. And I want to create a method accepting the resource name and return the drawable object. Then I wrote this

public Drawable getDrawable(String name){
int defaultResId=  ResourceOptimizer.getResId(name,R.drawable.class);
return getResources().getDrawable(defaultResId);
}

which the ResourceOptimizer is

public class ResourceOptimizer {
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;
    }
}
}

But the problem is that getResources() needs to be called in an activity or fragment, otherwise you to pass the context.

Passing the context might cause memory leak. Especially, when it has to be passed through several classes. I’m wondering if there is some way to get the resource by a better convenient way. like R.id.DRAWABLE_NAME

Alston
  • 2,085
  • 5
  • 30
  • 49
  • from where you are calling `getDrawable` method? it would more helpful if post more code. – Kishore Jethava Sep 15 '19 at 13:27
  • @KishoreJethava Outside a fragment or an activity. So I need to pass the context for several times because I like to extract methods. – Alston Sep 15 '19 at 13:34

1 Answers1

2

which the ResourceOptimizer is

Resources already has a getIdentifier() method.

But the problem is that getResources() needs to be called in an activity or fragment, otherwise you to pass the context.

Correct. Resources are only available by means of a suitable Context. Note that "suitable" depends on circumstances; for UIs, you almost always want to use the Context from your activity or fragment. For example, you might want different drawables based on whether the device is in dark mode or not on Android 10+.

Passing the context might cause memory leak

Not with the code that you have here, as you are not saving the Context, or anything from it, in a field that might outlive the Context itself.

I’m wondering if there is some way to get the resource by a better convenient way. like R.id.DRAWABLE_NAME

getDrawable() is a method on Context. So, call getDrawable(R.drawable.elephant).

Your code is trying specifically to avoid using R.drawable, instead using the String name. So, this turns into:

getDrawable(getResources().getIdentifier(yourString, "drawable", getPackageName()))

where yourString is the string basename of your resource (e.g., "elephant").

Ideally, you would cache the value returned by getIdentifier(), if you expect to retrieve the same resource by this code many times within the life of your process. Reflection is not cheap.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • So finally I still can't avoid to call `getResource()` when I need `drawable` resource. If I avoid to `save` the context state like using a static variable to point to the context, might it be safe? In what circumstances should I also avoid to pass context to avoid memory leak? Thanks. – Alston Sep 15 '19 at 13:39
  • 1
    @Alston: You want to ensure anything that uses the `Context` does not outlive the `Context`. In the case of UI, you want to ensure that anything that uses the `Activity` either does not outlive the `Activity` or is *very* carefully constructed to ensure it does not leak anything. A `static` field will outlive the `Context`, which is why we often use it as an example of what not to do. – CommonsWare Sep 15 '19 at 13:42
  • @CommonsWare So, it is not possible? I have icons, customized by the user. They always need to be the same. So they are not actually dependant of the context. I wish to access them through a repository. So I can access them through the dependecy injection. Any ideas on how I should proceed? – Quentin vk May 12 '20 at 11:37
  • 1
    @Lawnio: "I have icons, customized by the user" -- then they are not resources. Resources are the subject of this question and this answer. "Any ideas on how I should proceed?" -- I recommend that you read [this section of the documentation](https://developer.android.com/training/data-storage) and [this blog post series](https://commonsware.com/blog/2019/10/19/scoped-storage-stories-saf-basics.html). If you have additional concerns, I recommend that you ask a separate Stack Overflow question. – CommonsWare May 12 '20 at 11:47