¿Android, obteniendo ID de recurso de una cadena?

158

Necesito pasar un ID de recurso a un método en una de mis clases. Necesita usar tanto la identificación a la que apunta la referencia como también la cadena. ¿Cómo debería lograr esto mejor?

Por ejemplo:

R.drawable.icon

Necesito obtener la ID entera de esto, pero también necesito acceso a la cadena "icono".

Sería preferible si todo lo que tuviera que pasar al método es la cadena "icono".

Hamid
fuente
¿Es posible obtener de forma similar los archivos guardados en el almacenamiento interno? Tengo un problema porque debo suministrar una variedad de identificadores en lugar de ubicaciones a mi galería (pensé que es un adaptador) ... gracias
Ewoks
@Ewoks: no tienen ID en el almacenamiento interno. Son solo imágenes, si necesita algo para cargarlas en un montón de objetos Image y pasarlos, es posible que desee comenzar una nueva pregunta.
Hamid

Respuestas:

171

@EboMike: No sabía que Resources.getIdentifier()existía.

En mis proyectos usé el siguiente código para hacer eso:

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

Se usaría así para obtener el valor del R.drawable.iconvalor entero del recurso

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

Acabo de encontrar una publicación de blog que dice que Resources.getIdentifier()es más lento que usar la reflexión como lo hice. Compruébelo usted mismo .

Macarse
fuente
8
@Macarse: Actualmente, getIdentifier()tiene que hacer dos búsquedas de reflexión. En su ejemplo anterior, getIdentifier()usaría la reflexión para obtener Drawable.class, luego otra búsqueda de reflexión para obtener la ID del recurso. Eso explicaría la diferencia de velocidad. Dicho esto, ninguno de los dos es especialmente rápido y, por lo tanto, realmente debe almacenarse en caché (especialmente si se usa en un bucle o para filas en a ListView). Y el gran problema del enfoque de reflexión es que hace suposiciones sobre los componentes internos de Android que podrían cambiar en alguna versión futura.
CommonsWare
1
@CommonsWare: Eso es correcto. Estaba comprobando cómo se implementó Android y termina siendo una llamada nativa. gitorious.org/android-eeepc/base/blobs/… => gitorious.org/android-eeepc/base/blobs/…
Macarse
3
En su lugar, usaría una matriz entera con las ID. El uso de cadenas para ID no suena como el enfoque correcto.
EboMike
9
¿Por qué el contextparámetro?
Rudey
14
La llamada debe ser getId ("icono", R.drawable.class); no getResId ("icono", contexto, Drawable.class);
Smeet
80

Puede usar esta función para obtener la identificación del recurso.

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

Entonces, si desea obtener una función de llamada extraíble como esta

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

y para string puedes llamarlo así

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

Lee esto

Azhar
fuente
11
¿Cuál es el punto de hacer una función que simplemente llame a otra y "maneje" una posible excepción? Llame a getResources (). GetIdentifier () directamente.
Ricardo Meneghin Filho
37

Esto se basa en la respuesta @Macarse.

Use esto para obtener la identificación de recursos de una manera más rápida y amigable con el código.

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

Ejemplo:

getId("icon", R.drawable.class);
Daniel De León
fuente
30

Cómo obtener una identificación de recurso de aplicación del nombre del recurso es una pregunta bastante común y bien respondida.

La forma de obtener una identificación de recurso de Android nativa a partir del nombre del recurso está menos respondida. Aquí está mi solución para obtener un recurso extraíble de Android por nombre de recurso:

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

El método se puede modificar para acceder a otros tipos de recursos.

Martin Pearman
fuente
ahora .getResources (). getDrawable está en desuso if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){ return mContext.getDrawable(resourceId); } else { return mContext.getResources().getDrawable(resourceId); }
Evilripper
11

Si necesita emparejar una cadena y un int, ¿qué tal un mapa?

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
fuente
9

Puede usarlo Resources.getIdentifier(), aunque necesita usar el formato para su cadena como lo usa en sus archivos XML, es decir package:drawable/icon.

EboMike
fuente
Mi respuesta a continuación es lo contrario de esto. Pase la identificación del recurso y luego use getResourceEntryName(id)para buscar el nombre de la cadena. No te metas a buscar el "icono" del texto más largo.
Steve Waring
8

Me gustó esto, está funcionando para mí:

    imageView.setImageResource(context.getResources().
         getIdentifier("drawable/apple", null, context.getPackageName()));
Sarvar Nishonboev
fuente
7
Simple method to get resource ID:

public int getDrawableName(Context ctx,String str){
    return ctx.getResources().getIdentifier(str,"drawable",ctx.getPackageName());
}
Ivan Vovk
fuente
1
Sería mejor si solo proporcionara más información a su respuesta.
xMRi
6

Una forma sencilla de obtener la identificación de recursos de una cadena. Aquí resourceName es el nombre del recurso ImageView en la carpeta dibujable que también se incluye en el archivo XML.

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);
Muhammad Adil
fuente
Gracias hombre, fue realmente útil. Busqué mucho y no lo conseguí. Al ver su respuesta, descubrí que el segundo parámetro para getIdentifiertiene que ser id. Esto ni siquiera se mencionó en el sitio de desarrollo de Android. ¿de dónde sacaste esa información?
Prakash GPz
4

Como dijiste que solo querías pasar un parámetro y no parecía importar cuál, podrías pasar el identificador de recurso y luego averiguar el nombre de la cadena para ello, por lo tanto:

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

Esta podría ser la forma más eficiente de obtener ambos valores. No tiene que perder el tiempo buscando solo la parte del "icono" de una cadena más larga.

Steve Waring
fuente
2

En su res / layout / my_image_layout.xml

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

Para tomar ese ImageView por su valor de ID + +, dentro de su código Java haga esto:

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
fuente
2

El enfoque de Kotlin

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

Uso:

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

En MonoDroid / Xamarin.Android puedes hacer:

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

Pero dado que GetIdentifier no se recomienda en Android, puede usar Reflection de esta manera:

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

donde sugiero poner un try / catch o verificar las cadenas que está pasando.

Daniele D.
fuente
1

Para obtener la identificación Drawable del nombre del recurso de cadena, estoy usando este código:

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
fuente