studio - Crear hashmap/map a partir de recursos XML
linearlayout android studio (6)
Hoy me encontré con el mismo problema y estudiar developer.android.com durante mucho tiempo no me ayudó, ya que los recursos de Android no pueden ser hashes (mapas), solo arreglos.
Entonces encontré 2 maneras:
Tenga una serie de valores como "BEL | Bélgica", analice esas cadenas al principio del programa y almacénelas en un Mapa <>
Tener 2 matrices de cuerdas: primero con los valores de "BEL", "FRA", "SWE" y el segundo con "Bélgica", "Francia", "Suecia".
En segundo lugar es más sensible porque tiene que sincronizar los cambios y el orden en ambas matrices simultáneamente.
Estoy haciendo una aplicación donde un servicio web obtiene (entre otros) un montón de códigos de un servicio web (es decir, BEL, FRA, SWE). Durante el tiempo de ejecución, quiero traducir estos códigos a sus propios nombres para mostrarlos a los usuarios (es decir, Bélgica, Francia, Suecia). Puede haber muchos de estos códigos, por lo que me pregunto si existe alguna forma adecuada de almacenar la entrada (código, nombre) como un tipo de mapa en los recursos XML en Android, por lo que puedo buscar el nombre rápidamente por el código dado?
Aquí todo se trata de velocidad, ya que el mapa puede tener unos cientos de entradas.
Puede ser tarde para ti, pero para cualquier otra persona interesada. Si sus códigos de país de 3 dígitos son válidos, los códigos ISO 3166-1 alfa-3
Locale locale = new Locale("", "SWE");
String countryName = locale.getDisplayCountry();
Esto le da el nombre completo del país con el lenguaje correcto.
Creo que el enfoque más seguro y limpio aún no se ha publicado, así que aquí está mi $ 0.02:
¿Qué hay de la creación de un tipo de enumeración en el código que hace referencia al ID de recurso de cadena para su valor de visualización:
public enum Country {
FRA(R.string.france),
BEL(R.string.belgium),
SWE(R.string.sweden),
...;
@StringRes public int stringResId;
Country(@StringRes id stringResId) {
this.stringResId = stringResId;
}
}
Luego en strings.xml:
<string name="france">France</string>
...
Y cuando recibe un artículo del servicio web:
Country country = Country.valueOf(countryCodeFromServer);
context.getResources().getString(country.stringResId);
Las comprobaciones del tiempo de compilación asegurarán que cada país tenga un recurso para cada localidad, lo que no tendrá si mantiene la lista como un recurso de matriz.
La respuesta de Vladimir me pareció bastante convincente, así que implementé su primera sugerencia:
public SparseArray<String> parseStringArray(int stringArrayResourceId) {
String[] stringArray = getResources().getStringArray(stringArrayResourceId);
SparseArray<String> outputArray = new SparseArray<String>(stringArray.length);
for (String entry : stringArray) {
String[] splitResult = entry.split("//|", 2);
outputArray.put(Integer.valueOf(splitResult[0]), splitResult[1]);
}
return outputArray;
}
usarlo es sencillo. En su strings.xml
tiene una string-array
como esta:
<string-array name="my_string_array">
<item>0|Item 1</item>
<item>1|Item 4</item>
<item>2|Item 3</item>
<item>3|Item 42</item>
<item>4|Item 17</item>
</string-array>
y en su implementación:
SparseArray<String> myStringArray = parseStringArray(R.array.my_string_array);
También puede definir un mapa en XML, ponerlo en res / xml y analizar en HashMap ( sugerido en esta publicación ). Si desea mantener el análisis del orden de las claves en LinkedHashMap. La implementación simple sigue:
Recurso de mapa en res/xml
:
<?xml version="1.0" encoding="utf-8"?>
<map linked="true">
<entry key="key1">value1</entry>
<entry key="key2">value2</entry>
<entry key="key3">value3</entry>
</map>
Analizador de recursos:
public class ResourceUtils {
public static Map<String,String> getHashMapResource(Context c, int hashMapResId) {
Map<String,String> map = null;
XmlResourceParser parser = c.getResources().getXml(hashMapResId);
String key = null, value = null;
try {
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {
Log.d("utils","Start document");
} else if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("map")) {
boolean isLinked = parser.getAttributeBooleanValue(null, "linked", false);
map = isLinked ? new LinkedHashMap<String, String>() : new HashMap<String, String>();
} else if (parser.getName().equals("entry")) {
key = parser.getAttributeValue(null, "key");
if (null == key) {
parser.close();
return null;
}
}
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("entry")) {
map.put(key, value);
key = null;
value = null;
}
} else if (eventType == XmlPullParser.TEXT) {
if (null != key) {
value = parser.getText();
}
}
eventType = parser.next();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return map;
}
}
Tenía un requisito similar, y lo resolví de una manera que es más poderosa que las soluciones actuales.
Primero crea un recurso que sea una matriz de matrices de país:
<array name="countries_array_of_arrays">
<item>@array/es</item>
<item>@array/it</item>
</array>
Luego, para cada país, agregue una matriz con la información del país:
<array name="es">
<item>ES</item>
<item>ESPAÑA</item>
</array>
<array name="it">
<item>IT</item>
<item>ITALIA</item>
</array>
Algunas notas:
Los valores de
name
(es) en cada matriz de país deben coincidir con los decountries_array_of_arrays
(obtendrá un error si no lo hace).El orden de los elementos en cada matriz debe ser el mismo para todas las matrices. Por lo tanto, siempre ponga primero el código de país y el nombre del país en segundo lugar, por ejemplo.
Puede tener cualquier cantidad de cadenas para cada país, no solo el código de país y el nombre.
Para cargar las cadenas en tu código haz esto:
TypedArray countriesArrayOfArrays = getResources().obtainTypedArray(R.array.countries_array_of_arrays);
int size = countriesArrayOfArrays.length();
List<String> countryCodes = new ArrayList<>(size);
List<String> countryNames = new ArrayList<>(size);
TypedArray countryTypedArray = null;
for (int i = 0; i < size; i++) {
int id = countriesArrayOfArrays.getResourceId(i, -1);
if (id == -1) {
throw new IllegalStateException("R.array.countries_array_of_arrays is not valid");
}
countryTypedArray = getResources().obtainTypedArray(id);
countryCodes.add(countryTypedArray.getString(0));
//noinspection ResourceType
countryNames.add(countryTypedArray.getString(1));
}
if (countryTypedArray != null) {
countryTypedArray.recycle();
}
countriesArrayOfArrays.recycle();
Aquí estoy cargando los recursos a la List
2 pero puede usar un Map
si lo desea.
¿Por qué es esto más poderoso?
Le permite utilizar recursos de cadena y, por lo tanto, traducir los nombres de países para diferentes idiomas.
Le permite asociar cualquier tipo de recurso a cada país, no solo cadenas. Por ejemplo, puede asociar un
@drawable
con un indicador de país o un<string-array>
que contenga provincias / estados para el país.
Ejemplo avanzado:
<array name="it">
<item>IT</item>
<item>ITALIA</item>
<item>@drawable/flag_italy</item>
<item>@array/provinces_italy</item>
</array>
Tenga en cuenta que no lo he intentado pero lo he visto en otras preguntas . En tal caso, usaría countryTypedArray.getDrawable(2)
para obtener el dibujable, por ejemplo.
Simplificación:
Si solo está utilizando cadenas para la matriz de país, puede usar una <string-array
(en lugar de una <array>
) como esta:
<string-array name="it">
<item>IT</item>
<item>ITALIA</item>
</string-array>
Y puede simplificar un poco el código for-loop obteniendo directamente un String[]
lugar de un TypedArray
:
String[] countryArray = getResources().getStringArray(id);
countryCodes.add(countryArray[0]);
countryNames.add(countryArray[1]);
Una nota sobre tener 2 <string-array>
:
Inicialmente estaba pensando en tener 2 <string-array>
(uno para el código de país y otro para el nombre del país) como se menciona en otra respuesta. Sin embargo, con 2 <string-array>
debe asegurarse de que coincidan el número y el orden de los elementos. Con esta solución, no. Es más seguro en este sentido. Tenga en cuenta que, como ya he dicho, el orden de los elementos en cada matriz de país es importante: ¡siempre coloque el código de país y el nombre del país en el mismo orden!