从XML资源创buildhashmap / map

我正在做一个应用程序,其中一个Web服务从Web服务(即BEL,FRA,SWE)获取一堆代码。 在运行期间,我想把这些代码翻译成它们相应的名字以显示给用户(即比利时,法国,瑞典)。 可以有很多这些代码,所以我想知道是否有任何适当的方式来存储(代码,名称)条目作为某种地图在Android的XML资源,所以我可以快速获取名称给定的代码?

这是关于速度的一切,因为地图可以有几百个条目。

今天我遇到了同样的问题,研究developer.android.com很长一段时间没有帮助,因为Android资源不能哈希(地图),只有arrays。

所以我find了两种方法:

  1. 有一个像“BEL |比利时”的string数组,在程序的早期parsing这些string并存储在Map <>中

  2. 有两个string数组:首先是“BEL”,“FRA”,“SWE”,其次是“Belgium”,“France”,“Sweden”。

其次是更敏感的原因,你必须同时在两个arrays同步更改和顺序。

我发现弗拉基米尔的回答颇有说服力,所以我实施了他的第一个build议:

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

使用它是直接的。 在你的strings.xml你有一个像这样的string-array

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

并在您的实施:

 SparseArray<String> myStringArray = parseStringArray(R.array.my_string_array); 

你也可以用XML定义一个地图,把它放在res / xml中,然后parsing成HashMap( 在这篇文章中build议 )。 如果你想保持键顺序parsing到LinkedHashMap。 简单的实现如下:

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> 

资源parsing器:

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

我有类似的要求,我用比现有解决scheme更强大的方式来解决这个问题。

首先创build一个国家数组的数组资源:

 <array name="countries_array_of_arrays"> <item>@array/es</item> <item>@array/it</item> </array> 

然后为每个国家添加国家信息数组:

 <array name="es"> <item>ES</item> <item>ESPAÑA</item> </array> <array name="it"> <item>IT</item> <item>ITALIA</item> </array> 

一些说明:

  1. 每个国家/地区arrays上的name值(es,it)必须与countries_array_of_arraysname值相匹配(否则,您将得到一个错误)。

  2. 每个arrays上的项目顺序必须与所有arrays相同。 所以总是要把国家代码放在第一位,而把国家名放在第二位。

  3. 每个国家可以有任意数量的string,而不仅仅是国家代码和名称。

加载你的代码中的string做到这一点:

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

在这里,我正在加载资源到2 List但你可以使用一个Map如果你想。

为什么这更强大?

  1. 它允许你使用string资源,并因此翻译不同国家的语言。

  2. 它允许您将任何types的资源关联到每个国家,而不仅仅是string。 例如,您可以将@drawable与国家/地区或国家/地区的<string-array>关联@drawable

先进的例子:

 <array name="it"> <item>IT</item> <item>ITALIA</item> <item>@drawable/flag_italy</item> <item>@array/provinces_italy</item> </array> 

请注意,我没有尝试过,但是我在其他问题中看到过。 例如,在这种情况下,您将使用countryTypedArray.getDrawable(2)来获取drawable。

简化:

如果你只使用国家数组的string,你可以像这样使用<string-array (而不是<array> ):

 <string-array name="it"> <item>IT</item> <item>ITALIA</item> </string-array> 

您可以通过直接获取String[]而不是TypedArray来简化for循环代码:

 String[] countryArray = getResources().getStringArray(id); countryCodes.add(countryArray[0]); countryNames.add(countryArray[1]); 

有关2 <string-array>注意事项:

最初我在考虑在另一个答案中提到2 <string-array> (一个用于国家代码,另一个用于国家名称)。 但是,对于2 <string-array>您必须确保项目的数量顺序匹配。 有了这个解决scheme,你不需要。 在这方面更安全。 请注意,正如我所说的,每个国家/地区arrays上的项目顺序很重要:始终将国家代码和国家/地区名称放在同一顺序!

对你来说可能会迟到,但对于任何感兴趣的人来说。 如果您的3位国家代码是有效的ISO 3166-1 alpha-3代码

 Locale locale = new Locale("", "SWE"); String countryName = locale.getDisplayCountry(); 

这给完整的国家名称与正确的语言。

我认为最安全和最干净的方法还没有发布,所以这是我的0.02美元:

如何在引用string资源ID的代码中为其显示值创build一个枚举types:

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

然后在strings.xml中:

 <string name="france">France</string> ... 

当你从networking服务收到一个项目时:

 Country country = Country.valueOf(countryCodeFromServer); context.getResources().getString(country.stringResId); 

构build时间检查将确保每个国家/地区都有一个针对每个语言环境的资源,如果将该列表作为数组资源来维护,则不会有这些资源。