androidmemory-leaksgetresource

How to get resource without context in Android?


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


Solution

  • 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.