从XML资源创建hashmap/map

从XML资源创建hashmap/map,xml,android,Xml,Android,我正在制作一个应用程序,其中一个web服务从一个web服务(即BEL、FRA、SWE)获取(除其他外)一组代码。在运行期间,我希望将这些代码转换为相应的名称,以显示给用户(即比利时、法国、瑞典)。可能有很多这样的代码,所以我想知道是否有合适的方法将(code,name)条目作为某种映射存储在Android的XML资源中,这样我就可以通过给定的代码快速获取名称了 这一切都与速度有关,因为地图可以有几百个条目。今天我遇到了同样的问题,学习developer.android.com很长一段时间都没有帮

我正在制作一个应用程序,其中一个web服务从一个web服务(即BEL、FRA、SWE)获取(除其他外)一组代码。在运行期间,我希望将这些代码转换为相应的名称,以显示给用户(即比利时、法国、瑞典)。可能有很多这样的代码,所以我想知道是否有合适的方法将(code,name)条目作为某种映射存储在Android的XML资源中,这样我就可以通过给定的代码快速获取名称了


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

今天我遇到了同样的问题,学习developer.android.com很长一段时间都没有帮助,因为android资源不能是散列(地图),只能是数组

所以我找到了两种方法:

  • 拥有一个字符串数组,如“Bell | Belgium”,在程序早期解析这些字符串并存储在映射中

  • 有两个字符串数组:第一个字符串数组的值为“BEL”、“FRA”、“SWE”,第二个字符串数组的值为“比利时”、“法国”、“瑞典”


  • 第二个更为敏感,因为您必须同时同步两个数组中的更改和顺序。

    您还可以用XML定义映射,将其放在res/XML中并解析为HashMap()。如果要保持密钥顺序,请解析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>
    
    
    价值1
    价值2
    价值3
    
    资源分析器:

    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;
        }
    }
    
    公共类ResourceUtils{
    公共静态映射getHashMapResource(上下文c,int hashMapResId){
    Map=null;
    XmlResourceParser=c.getResources().getXml(hashMapResId);
    字符串键=null,值=null;
    试一试{
    int eventType=parser.getEventType();
    while(eventType!=XmlPullParser.END_文档){
    if(eventType==XmlPullParser.START\u文档){
    日志d(“utils”、“启动文件”);
    }else if(eventType==XmlPullParser.START_标记){
    if(parser.getName().equals(“map”)){
    boolean isLinked=parser.getAttributeBoleAnValue(null,“linked”,false);
    map=isLinked?新建LinkedHashMap():新建HashMap();
    }else if(parser.getName().equals(“条目”)){
    key=parser.getAttributeValue(null,“key”);
    if(null==键){
    parser.close();
    返回null;
    }
    }
    }else if(eventType==XmlPullParser.END_标记){
    if(parser.getName().equals(“条目”)){
    map.put(键、值);
    key=null;
    值=空;
    }
    }else if(eventType==XmlPullParser.TEXT){
    if(null!=键){
    value=parser.getText();
    }
    }
    eventType=parser.next();
    }
    }捕获(例外e){
    e、 printStackTrace();
    返回null;
    }
    返回图;
    }
    }
    
    我发现弗拉基米尔的建议很有说服力,所以我实施了他的第一个建议:

    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;
    }
    
    在实施过程中:

    SparseArray<String> myStringArray = parseStringArray(R.array.my_string_array);
    
    SparseArray myStringArray=parseStringArray(R.array.my_string_数组);
    
    对你来说可能已经晚了,但对其他感兴趣的人来说可能已经晚了。 如果您的3位国家/地区代码是有效的ISO 3166-1 alpha-3代码

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

    这提供了完整的国家名称和正确的语言。

    我有一个类似的要求,我以一种比当前解决方案更强大的方式解决了它

    首先创建一个资源,该资源是一个国家/地区数组数组:

    <array name="countries_array_of_arrays">
        <item>@array/es</item>
        <item>@array/it</item>
    </array>
    
    在这里,我正在将资源加载到2
    列表
    ,但是如果需要,您可以使用
    映射

    为什么这个功能更强大?

  • 它允许您使用字符串资源,从而翻译不同语言的国家名称

  • 它允许您将任何类型的资源关联到每个国家,而不仅仅是字符串。例如,您可以将
    @drawable
    与国旗或包含该国家的省/州的
    关联

  • 高级示例:

    <array name="it">
        <item>IT</item>
        <item>ITALIA</item>
        <item>@drawable/flag_italy</item>
        <item>@array/provinces_italy</item>
    </array>
    
    您可以通过直接获取
    字符串[]
    而不是
    类型Darray来简化for循环代码:

    String[] countryArray = getResources().getStringArray(id);
    countryCodes.add(countryArray[0]);
    countryNames.add(countryArray[1]);
    
    关于拥有2个

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

    最初,我想有2个
    (一个代表国家代码,另一个代表国家名称),如另一个答案中所述。但是,使用2
    时,您必须确保项目的数量和顺序匹配。有了这个解决方案,你就不需要了。在这方面比较安全。请注意,正如我所说,每个国家/地区数组中项目的顺序很重要:始终将国家/地区代码和国家/地区名称放在相同的顺序中

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

    如何在代码中创建一个枚举类型,该类型引用字符串资源id作为其显示值:

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

    构建时检查将确保每个国家/地区对每个区域设置都有一个资源,如果将列表作为数组资源维护,则不会有该资源

    作为替代方案,您可以将json对象存储在资产中,并使用第二种方法将其解析为MapUse,并通过测试强制执行同步。我实际上更喜欢(至少是原则,因为答案本身相当冗长)。您应该像这样转义管道(“\\\”)字符:“\\\\\”让你的代码正常工作。@limlim你测试过吗?上面的解决方案对我有效,但我很乐意编辑我的帖子。是的,我测试过了。在添加丢失的转义后,它就像一个符咒!您可以在代码中进行转义,从而使XML更干净。也就是说,XML和
    中的
    0 | Item1
    String[] countryArray = getResources().getStringArray(id);
    countryCodes.add(countryArray[0]);
    countryNames.add(countryArray[1]);
    
    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;
       }
    } 
    
    <string name="france">France</string>
    ...
    
    Country country = Country.valueOf(countryCodeFromServer);
    context.getResources().getString(country.stringResId);