从XML资源创buildhashmap / map
我正在做一个应用程序,其中一个Web服务从Web服务(即BEL,FRA,SWE)获取一堆代码。 在运行期间,我想把这些代码翻译成它们相应的名字以显示给用户(即比利时,法国,瑞典)。 可以有很多这些代码,所以我想知道是否有任何适当的方式来存储(代码,名称)条目作为某种地图在Android的XML资源,所以我可以快速获取名称给定的代码?
这是关于速度的一切,因为地图可以有几百个条目。
今天我遇到了同样的问题,研究developer.android.com很长一段时间没有帮助,因为Android资源不能哈希(地图),只有arrays。
所以我find了两种方法:
-
有一个像“BEL |比利时”的string数组,在程序的早期parsing这些string并存储在Map <>中
-
有两个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>
一些说明:
-
每个国家/地区arrays上的
name
值(es,it)必须与countries_array_of_arrays
的name
值相匹配(否则,您将得到一个错误)。 -
每个arrays上的项目顺序必须与所有arrays相同。 所以总是要把国家代码放在第一位,而把国家名放在第二位。
-
每个国家可以有任意数量的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
如果你想。
为什么这更强大?
-
它允许你使用string资源,并因此翻译不同国家的语言。
-
它允许您将任何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时间检查将确保每个国家/地区都有一个针对每个语言环境的资源,如果将该列表作为数组资源来维护,则不会有这些资源。