Si le hablas a un cliente sobre gestión de recursos en Android, seguramente ponga cara rara y piense que le estás hablando de servidores o de dinero. Pero en realidad, cuando hablamos de recursos en Android nos referimos a todo ese material estático (imágenes, textos, colores, dimensiones…) que hace que una app se vea y se comporte como toca, sin tenerlo metido a lo bruto dentro del código. Y créeme: entender bien cómo funcionan marca la diferencia entre una app cutre y un proyecto profesional y fácil de mantener.
La idea clave es que todos esos archivos externos se guardan en la carpeta res/ del proyecto Android, organizados por tipo y, cuando hace falta, por configuración del dispositivo (idioma, densidad de pantalla, modo noche, etc.). Android se encarga en tiempo de ejecución de elegir el recurso que mejor encaja con el móvil o tablet que tiene el usuario en la mano, sin que tú tengas que llenar el código de if/else para cada caso.
¿Qué es exactamente un recurso en Android?
En Android, un recurso es cualquier archivo externo o valor estático que está asociado a tu aplicación y que se usa en tiempo de ejecución sin estar incrustado directamente en el código fuente. Hablamos de imágenes (bitmaps), cadenas de texto, colores, dimensiones, estilos, animaciones, archivos de audio o vídeo, e incluso configuraciones XML personalizadas.
En lugar de escribir textos, colores o rutas de imágenes en el código, en Android lo habitual es referirse a todo con IDs de recurso generados en la clase R. Esa pequeña “indirección” permite cambiar textos, imágenes o estilos sin recompilar la lógica de la app, mantener versiones para distintos idiomas o tipos de pantalla y, sobre todo, que diseñadores y desarrolladores puedan trabajar en paralelo sin pisarse.
Todos estos recursos viven en la carpeta res/ del proyecto. Ahí se agrupan en subdirectorios con nombres muy específicos, porque el nombre de cada carpeta indica el tipo de recurso y, opcionalmente, la configuración de dispositivo a la que va dirigido (por ejemplo, idioma, orientación o densidad de pantalla). Android usa esa estructura para decidir qué archivo cargar en cada momento.
Cómo se agrupan los recursos: la carpeta res/ y sus subdirectorios
Dentro de res/ cada tipo de recurso va en un subdirectorio concreto. No se pueden dejar archivos sueltos en res/, siempre deben ir dentro de una carpeta con un nombre admitido; de lo contrario, el compilador fallará. En un proyecto muy sencillo podrías tener algo así:
MyProject/
src/
MyActivity.kt
res/
drawable/ graphic.png
mipmap/ icon.png
values/ strings.xml
Esta estructura se puede complicar bastante en una app real, pero la base es la misma: cada carpeta de res describe un tipo de recurso y Android genera, a partir de todo ello, la clase R con sus IDs.
Principales directorios de recursos admitidos
A continuación tienes los directorios más habituales y qué tipo de archivos deben contener. Son la base tanto en aplicaciones “clásicas” con layouts XML como en apps modernas con Jetpack Compose (aunque en Compose algunos de ellos hayan quedado en segundo plano).
drawable/ – Recursos gráficos y XML de diseño
En res/drawable/ se guardan los recursos gráficos generales: mapas de bits PNG, JPG, GIF, versiones nine-patch (.9.png) y también ficheros XML que describen elementos gráficos que se compilan como “drawables”. Desde el código se accede a todos ellos a través de R.drawable.
Dentro de drawable se admiten varios subtipos de recursos definidos por XML, por ejemplo: listas de estados, formas, animaciones de vista y otros elementos gráficos reutilizables. Estos XML permiten definir botones con cambios de color según el estado, fondos redondeados, selectores, etc., sin tener que generar una imagen por cada variación.
mipmap/ – Iconos de la app por densidad
La carpeta res/mipmap/ se usa específicamente para los iconos de la aplicación (por ejemplo, ic_launcher.png) en sus distintas densidades de pantalla. Se acceden con R.mipmap, aunque en muchas herramientas verás que Android trata los iconos casi como un caso especial.
La idea es guardar en estas carpetas versiones del mismo icono pensadas para diferentes densidades (mdpi, hdpi, xhdpi, etc.), usando calificadores como mipmap-hdpi/ o mipmap-xxxhdpi/. El sistema escoge automáticamente el icono con la densidad adecuada para que se vea nítido en cada dispositivo sin que tú tengas que preocuparte por el escalado.
raw/ – Archivos binarios sin procesar
En res/raw/ puedes guardar ficheros de cualquier tipo que quieras leer como datos sin procesar: audio, vídeo, JSON, binarios, etc. Todos reciben un ID en R.raw y se pueden abrir como flujo de bytes con Resources.openRawResource(R.raw.nombre).
La diferencia frente a la carpeta assets/ es importante: lo que hay en res/raw tiene ID de recurso y se maneja por ID entero; lo que hay en assets no tiene ID, se accede por ruta usando AssetManager y se mantiene su nombre y jerarquía de subcarpetas originales.
values/ – Strings, colores, dimensiones, estilos y más
La carpeta res/values/ contiene ficheros XML con valores simples: cadenas de texto, enteros, booleanos, dimensiones, colores, arrays, estilos, etc. En este caso, un solo archivo puede definir muchos recursos distintos, porque cada hijo de <resources> (por ejemplo, <string>, <color>, <dimen>, <style>) genera su propio ID en la clase R.
Por convención se suele separar cada tipo de valor en su archivo, para que todo sea más legible: strings.xml, colors.xml, dimens.xml, styles.xml, arrays.xml…. Pero no es obligatorio; Android solo se fija en el tipo de elemento XML y en el atributo name, no en el nombre del archivo.
Los recursos más habituales en values incluyen:
- R.string: cadenas de texto, mensajes, títulos, etc.
- R.color: colores simples o referencias a listas de estado.
- R.dimen: tamaños, márgenes, paddings en dp/sp.
- R.bool, R.integer: flags booleanos, valores numéricos.
- R.array, R.plurals: arrays de valores y plurales localizados.
- R.style: estilos reutilizables para vistas o temas completos.
xml/ – Configuraciones XML arbitrarias
En res/xml/ se almacenan archivos XML de configuración genérica que la app leerá en tiempo de ejecución con Resources.getXML(). Suele usarse para preferencias, definiciones de proveedores de contenido, configuraciones de navegación y otros ajustes estructurados que no encajan en values.
font/ – Tipos de letra como recursos
La carpeta res/font/ permite declarar fuentes TTF, OTF, TTC y también XML con <font-family>. De esta forma, las tipografías se tratan como recursos, con IDs en R.font, y se aplican desde código o desde XML sin necesidad de cargarlas manualmente desde assets.
Esto simplifica mucho la definición de tipografías para temas y estilos, y mejora la compatibilidad con el sistema (soporte de fuentes descargables, por ejemplo).
Otros directorios clásicos: animator, anim, layout, menu, color
En las apps basadas en vistas y layouts XML es muy habitual encontrarse estas carpetas adicionales en res/:
- animator/: XML que describen animaciones de propiedades (Property Animations), accesibles como
R.animator. - anim/: XML para animaciones de vistas (tween animations), accesibles como
R.anim. - layout/: XML que definen la estructura visual de pantallas y fragmentos, con IDs en
R.layout. - menu/: definiciones XML de menús de opciones, contextuales y similares, accesibles con
R.menu. - color/: listas de estados de color en XML, que permiten cambiar el color según el estado del componente, accesibles vía
R.color.
En aplicaciones modernas con Jetpack Compose, gran parte de las interfaces, animaciones y colores controlados por estado se definen directamente en Kotlin, así que carpetas como layout/, menu/, anim/, animator/ y parte de color/ pierden relevancia. Aun así, siguen existiendo para mantener compatibilidad con vistas y proyectos híbridos.
Recursos alternativos: adaptarse a idioma, densidad, tamaño y más
Una de las grandes fortalezas de Android es su capacidad para elegir automáticamente la versión de un recurso que mejor encaja según la configuración del dispositivo: idioma, región, tamaño de pantalla, densidad de píxeles, modo noche, tipo de interfaz (coche, TV, reloj), HDR, gamut de color, etc.
Para conseguirlo, Android permite crear directorios de recursos alternativos usando calificadores en el nombre de la carpeta con este patrón: <tipo_recurso>-<calificador1>-<calificador2>.... Por ejemplo: drawable-hdpi/, values-es/ o drawable-en-night/.
Cómo definir un recurso alternativo
El procedimiento general para ofrecer variaciones de un mismo recurso es muy sencillo:
- Crea un nuevo directorio dentro de res/ cuyo nombre siga el formato
<nombre_base>-<calificador(es)>. El nombre base es el directorio de recursos “normal” (drawable, layout, values, mipmap, etc.) y los calificadores describen la configuración concreta; por ejemplo, values-es-rMX para español de México. - Coloca en ese directorio los mismos archivos de recurso que en el directorio base (mismo nombre de archivo), pero con contenido adaptado a esa configuración. Android usará siempre los IDs de R del archivo base, pero cargará la versión localizada o adaptada.
Un ejemplo clásico sería:
res/
drawable/
icon.png
background.png
drawable-hdpi/
icon.png
background.png
El directorio drawable/ contiene los gráficos por defecto y drawable-hdpi/ las versiones para pantallas de alta densidad. El ID del recurso sigue siendo R.drawable.icon o R.drawable.background, y Android escoge en tiempo de ejecución qué fichero usar.
Es fundamental que cada recurso alternativo tenga su equivalente predeterminado sin calificadores (por ejemplo, en values/ o drawable/). Si solo defines una cadena en values-en/ y no en values/, la app puede lanzar una ResourceNotFoundException al cambiar el idioma del sistema o al ejecutarse en una configuración que no habías previsto.
Principales calificadores de configuración (Tabla de referencia)
Android define una lista larga de calificadores de configuración para etiquetar carpetas de recursos. Se aplican en un orden de precedencia determinado, y es obligatorio mantener ese orden al combinarlos. Algunos de los más relevantes son:
- MCC y MNC (por ejemplo,
mcc310,mcc310-mnc004): identifican país y red móvil a partir de la SIM. Se usan para casos muy específicos (p. ej. requisitos legales por país). - Idioma, script y región: clásico
es-rES,en-rUSo etiquetas BCP 47 del tipob+es+419para Latinoamérica,b+zh+Hantpara chino tradicional, etc. Permiten ofrecer cadenas, gráficos o layouts adaptados a idioma y variante regional. - Género gramatical:
masculine,feminine,neuter, para idiomas donde el género afecta a los textos (como el francés). Podrías tenervalues-fr-masculine/,values-fr-feminine/, etc. - Gamut de color:
widecgonowidecgpara pantallas con gamut amplio (Display P3, AdobeRGB) o estándar (sRGB). Permiten ajustar colores o gráficos para pantallas más ricas. - HDR:
highdrolowdrsegún la capacidad de rango dinámico de la pantalla. Útil para vídeo o gráficos con alto contraste. - Modo de IU:
car,desk,television,appliance,watch,vrheadset. Sirve para adaptar layouts y recursos si la app se ejecuta en un coche, TV o reloj. - Modo noche:
nightynotnight. Permite tener paletas de colores, drawables o layouts diferentes para tema oscuro o claro sin cambiar código. - Densidad de píxeles (dpi):
ldpi,mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi,tvdpi,nodpi,anydpi,nnndpi. Controlan qué versión de cada imagen se carga en función de la densidad real de la pantalla; el sistema prefiere siempre escalar hacia abajo (imágenes más grandes) que hacia arriba. - Tamaño de pantalla y medidas en dp: calificadores clásicos como
small,normal,large,xlargeo más modernos comosw600dp,w720dp,h720dp, que especifican anchura/altura mínima disponible. - Orientación:
port(vertical) yland(horizontal), para layouts distintos en retrato y apaisado, comolayout-land/. - Tipo y disponibilidad de teclado, navegación y pantalla táctil:
finger,notouch,qwerty,12key,keysexposed,keyssoft,navexposed,dpad,trackball, etc., bastante útiles en dispositivos especializados. - Versión de la plataforma:
v4,v7,v21, etc., para recursos específicos de un nivel de API hacia arriba.
En apps modernas con Compose, muchos calificadores relacionados con diseño y dimensiones (como ancho/alto disponible, dirección de layout, relación de aspecto, pantalla redonda…) dejan de ser tan necesarios, porque la composición y el sistema de temas se controlan desde el código Kotlin.
Reglas importantes al usar calificadores
Al crear carpetas de recursos alternativos hay una serie de normas que conviene no saltarse para evitar sorpresas:
- Puedes combinar varios calificadores en un mismo directorio, separados por guiones: por ejemplo,
drawable-en-rUS-nightaplicará a dispositivos en inglés de Estados Unidos cuando estén en modo noche. - El orden de los calificadores es obligatorio y debe seguir la precedencia oficial (primero idioma, luego tamaño de pantalla, luego densidad, etc.). Una carpeta
drawable-hdpi-night/es incorrecta; debe serdrawable-night-hdpi/. - No se pueden anidar directorios de recursos alternativos. No vale tener
res/drawable/drawable-en/; en su lugar se usará directamenteres/drawable-en/. - Los nombres no distinguen mayúsculas/minúsculas; el compilador los pasa a minúsculas, así que escribir
drawable-Enodrawable-enes lo mismo (aunque por legibilidad se recomienda mantener minúsculas). - Solo se admite un valor por tipo de calificador. Si quieres recursos para España y Francia, no puedes usar
drawable-es-fr/, sinodrawable-es/ydrawable-fr/con los mismos nombres de archivo dentro.
Una vez creadas todas estas carpetas, Android se encarga de elegir el recurso que mejor coincide cada vez que solicitas un ID, descartando directorios incompatibles y aplicando la precedencia correcta de calificadores.
Cómo decide Android qué recurso cargar
Cuando pides, por ejemplo, R.drawable.icon, y existen múltiples variaciones, el sistema compara la configuración actual del dispositivo (idioma, densidad, modo noche, etc.) con todos los directorios que contienen un archivo llamado icon. El proceso, simplificado, es este:
- Descarta los directorios de recursos que se contradicen con la configuración del dispositivo (por ejemplo, un
drawable-fr-rCA/si el idioma es en-GB). La densidad de pantalla es la única excepción: no se descarta de entrada, porque siempre es “ajustable”. - Recorre los calificadores en orden de precedencia (MCC/MNC, idioma, tamaño de pantalla, densidad, modo noche, etc.) y comprueba si hay directorios que usan cada calificador.
- Si ningún directorio usa un calificador concreto, pasa al siguiente. Si sí lo usan, descarta los que no lo tengan, quedándose solo con los que encajan mejor.
- En el caso de la densidad, en lugar de descartar simplemente, elige la densidad más cercana a la del dispositivo, con preferencia por escalar hacia abajo.
- Repite el proceso hasta que quede un único directorio candidato, del cual se toma el recurso final.
Un detalle importante es que la precedencia de calificadores pesa más que el número total de coincidencias. Es decir, Android prefiere un directorio que coincide en idioma aunque no coincida en otros calificadores de menor prioridad antes que uno que coincide en varios aspectos, pero no en el idioma.
Alias de recursos: reutilizar sin duplicar archivos
Muchas veces necesitas que varias configuraciones distintas usen el mismo archivo, pero no quieres copiarlo a cada carpeta alternativa. Para eso existen los alias de recursos, que permiten apuntar desde un recurso alternativo a otro recurso ya existente.
Alias para drawables mediante XML
Imagina que tienes un icono de la app, pero para ciertas configuraciones regionales quieres una versión distinta, y para otras dos regiones quieres compartir la misma imagen. Una forma limpia de hacerlo es guardar la imagen compartida con otro nombre, por ejemplo icon_ca.png, en res/drawable/, y luego crear archivos XML en los directorios regionales que actúen como alias:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/icon_ca" />
Este XML se guardaría como icon.xml en res/drawable-en-rCA/ y res/drawable-fr-rCA/, por ejemplo. Entonces, cuando tu código pida R.drawable.icon, el sistema resolverá el alias y acabará cargando icon_ca.png para esas configuraciones, manteniendo una sola copia física de la imagen.
Alias para strings, colores y otros valores simples
En el caso de valores simples en values/ (strings, colores, etc.), los alias se crean usando como valor la referencia al recurso original. Por ejemplo, para cadenas podrías hacer:
<resources>
<string name="hello">Hola</string>
<string name="hi">@string/hello</string>
</resources>
Ahora R.string.hi será un alias de R.string.hello, de forma que cualquier cambio en “hello” se reflejará automáticamente en “hi”.
Con los colores funciona igual:
<resources>
<color name="red">#f00</color>
<color name="highlight">@color/red</color>
</resources>
El recurso R.color.highlight simplemente apunta a R.color.red. Es una manera muy útil de crear nombres semánticos (por ejemplo, primary, accent, error) sin dejar de reutilizar el mismo valor real.
Cómo acceder a los recursos desde código (vistas y Compose)
Cuando se compila tu app, la herramienta de compilación genera la clase R que agrupa todos los IDs de recursos definidos en res/. Para cada tipo hay una subclase: R.drawable, R.string, R.layout, R.color, etc., y cada recurso se representa como un entero estático.
La sintaxis general para referenciar un recurso desde código Java/Kotlin es:
[<package_name>.]R.<tipo_recurso>.<nombre_recurso>
- <package_name>: el paquete donde se ubica el recurso (normalmente se omite dentro del propio módulo).
- <tipo_recurso>: la subclase de R (string, drawable, layout, color, etc.).
- <nombre_recurso>: nombre definido en el archivo XML (atributo
name) o nombre de archivo sin extensión.
Por ejemplo: R.string.app_name, R.drawable.icon, R.layout.activity_main.
Acceso a recursos en Jetpack Compose
En Compose, existen helpers específicos y “conscientes de la composición” para acceder a los recursos de forma segura:
- Cadenas:
stringResource(id = R.string.hello) - Drawables:
painterResource(id = R.drawable.my_icon)
Estas funciones se integran con el sistema de recomposición, de manera que si cambia la configuración (por ejemplo, el idioma) y el composable se vuelve a dibujar, automáticamente se usan las variaciones correctas de cada recurso.
Acceder a recursos fuera de la IU
En capas como ViewModel, Repository o servicios, donde no tienes un composable o una vista directamente, puedes resolver recursos a través de Context. Un ejemplo típico sería:
val greeting = context.getString(R.string.hello_world)
Si necesitas algo más avanzado, puedes obtener un objeto Resources desde el contexto con context.resources y usar métodos como getColor, getDimension, openRawResource, etc.
Acceder a recursos de plataforma
Android también incluye recursos estándar del sistema (iconos, estilos, temas, cadenas) accesibles por la misma vía, pero anteponiendo el paquete android. Por ejemplo:
android.R.drawable.ic_menu_info_detailspara un icono del sistema.android.R.style.Theme_Materialpara un tema estándar.
Esto te permite reutilizar la apariencia y los patrones del sistema sin tener que copiar recursos manualmente.
Cuándo usar assets/ en lugar de res/
Aunque lo habitual es guardar casi todo en res/, hay casos en los que necesitas acceder a los archivos originales, con sus nombres y estructura de directorios intactos. En esos casos, los recursos deben ir en assets/, no en res/.
Los archivos en assets no reciben ID en la clase R; se accede a ellos a través de AssetManager, indicando rutas relativas, y siempre en modo lectura. Esto se usa sobre todo para ficheros estáticos grandes, plantillas, motores de juego, bases de datos pre-llenadas, etc., donde quieres controlar la jerarquía de carpetas de forma manual.
Si solo necesitas leer datos sin procesar y te basta con una referencia por ID, res/raw/ suele ser la opción más simple, ya que se integra con el resto del sistema de recursos.
Compatibilidad entre dispositivos: recursos predeterminados y nuevos calificadores
Para que tu app sea robusta en todo tipo de dispositivos y versiones de Android, es crucial que siempre definas recursos predeterminados para cada tipo que uses. Esos recursos sin calificadores actúan como “red de seguridad” cuando el sistema no encuentra ninguna coincidencia más específica.
Esto es importante por dos motivos: por un lado, porque no puedes prever todas las configuraciones posibles (idiomas, tamaños, densidades nuevas que aparezcan en el futuro), y por otro, porque algunas versiones antiguas de Android no entienden ciertos calificadores modernos. Si usas solo directorios con esos nuevos calificadores y sin una variante base, en versiones antiguas no habrá nada que coincida y la app puede fallar.
La excepción a esta regla son los recursos gráficos por densidad cuando tu minSdkVersion es 4 o superior: aunque no tengas un drawable “base” sin calificador, Android es capaz de elegir la densidad más cercana y escalar las imágenes, siempre que hayas proporcionado variantes para al menos varias densidades estándar. Aun así, lo ideal es cubrir los principales buckets (mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi) para minimizar el escalado y garantizar nitidez.
Al final, toda la gestión de recursos en Android gira alrededor de una idea muy simple: separas contenido estático de la lógica, organizas ese contenido por tipo y por configuración de dispositivo, y dejas que el sistema se encargue de elegir la mejor versión en cada contexto. Si aplicas bien estos principios (externalizar strings, colores y dimensiones, usar calificadores con cabeza, evitar duplicados mediante alias y apoyarte en Context o Compose para acceder a los recursos), tus apps serán más fáciles de mantener, de traducir, de adaptar a nuevas pantallas y, sobre todo, más agradables de evolucionar con el tiempo sin tener que rehacerlo todo desde cero.

