安卓:是否可以在XML文件中定义地图?

24

我试图定义一个利用资源的静态哈希表,但由于无法静态访问资源而被阻挡。

然后我意识到,在资源文件中定义静态映射是最好的选择。

如何在XML中定义一个映射? 我认为如果可能的话,应该类似于Listpreference机制,具有条目和条目值。


请查看以下内容:http://mobiforge.com/developing/story/using-google-maps-android?dm_switcher=true - dreamcoder
请问您能否举个例子,您想要具体做什么? - Blehi
1
Blehi,我想要一个静态地图,可以从任何类中多次访问。理想情况下,我希望它看起来像这样:<map name="food"> <item key="@string/apple" value="12"/> <item key="@string/banana" value="10"/> <item key="@string/soup" value="5"/> </map> - ilomambo
5个回答

42

更简单的选择是使用两个数组。这样做的好处是不必再次迭代XML文件,代码量更少,并且使用不同类型的数组更为简单。

<string-array name="myvariablename_keys">
   <item>key1</item>
   <item>key1</item>
</string-array>


<string-array name="myvariablename_values">
   <item>value1</item>
   <item>value2</item>
</string-array>

那么你的Java代码将如下所示:

String[] keys = this.getResources().getStringArray(R.array.myvariablename_keys);
String[] values = this.getResources().getStringArray(R.array.myvariablename_values);
LinkedHashMap<String,String> map = new LinkedHashMap<String,String>();
for (int i = 0; i < Math.min(keys.length, values.length); ++i) {
   map.put(keys[i], values[i]);
}

1
这是一个很好的解决方案,在AOSP内部用于许多情况。但要小心,因为只有在地图足够小且可以编辑而不会导致对齐问题以及不会面临本地化问题时才适用。例如,如果您只打算本地化值而不是键,如果需要添加新键,则这将成为维护噩梦。但是,在许多情况下,这是最佳选择。 - Brent K.
@BrentK。这就是为什么你应该始终引用字符串资源而不是硬编码的字符串。 - Oz Shabat
对于Kotlin,您可以使用以下代码从数组创建Map:keys.zip(values).toMap() - YaMiN

33

我该如何在XML中定义一个Map?

<thisIsMyMap>
  <entry key="foo">bar</entry>
  <entry key="goo">baz</entry>
  <!-- as many more as your heart desires -->
</thisIsMyMap>
将这个文件放在 res/xml/ 目录下,然后使用 getResources().getXml() 加载它。遍历事件以构建一个 HashMap<String, String>

1
这不是我需要的。实际上,我需要XML中的表部分。但是在我想要构建哈希映射的静态上下文中,我无法使用getResources()。 - ilomambo
2
@ilomambo:在自定义的Application子类的onCreate()中初始化您的哈希映射。这将在创建任何ContentProviders之后调用,但在您的应用程序的任何其他内容运行之前进行调用。Application是一个Context,应该适用于解析此XML文件。 - CommonsWare
3
这个例子不完整。编写XML很容易,但编写解析器很慢且麻烦。请参考我下面提供的示例,这是一个简单得多的解决方案。 - vangorra
1
@androiddeveloper:<entry key="foo"><item>bar</item><item>baz</item><item>goo</item></entry>。或者<entry key="foo"><item value="bar"/><item value="baz"/><item value="goo"/></entry>。或者<entry key="foo"><array><item>bar</item><item>baz</item><item>goo</item></array></entry>。或其他任何形式。XML绝对可以处理您在Java中选择建模为数组的元素集合。 - CommonsWare
1
@androiddeveloper:“Android的解析器怎么样?”-- Android有三个XML解析器。所有解析器都可以解析该XML。“我需要将xml文件作为参数传递…”-- Firebase应该记录该XML资源需要看起来像什么。无论你还是我都不能决定它应该长成什么样子。而Firebase是否处理数组与XML处理数组是两个非常不同的问题。 - CommonsWare
显示剩余8条评论

12
您始终可以将 Json 嵌入到您的 strings.xml 文件中:

res/values/strings.xml

<string name="my_map">{"F":"FOO","B":"BAR"}</string>

在您的Activity中,您可以在onStart方法中构建您的地图:

private HashMap<String, String> myMap;

@Override
protected void onStart() {
    super.onStart();
    myMap = new Gson().fromJson(getString(R.string.my_map), new TypeToken<HashMap<String, String>>(){}.getType());
}

这段代码需要使用Google Gson API才能正常运行。您可以使用Android SDK中内置的Json API来实现。

对于静态访问Map,您可以创建一个静态方法:

private static HashMap<String, String> method(Context context) {
    HashMap<String, String> myMap = new Gson().fromJson(context.getString(R.string.serve_times), new TypeToken<HashMap<String, String>>(){}.getType());
    return myMap;
}

在这种情况下,最好将其保存为位于资产文件夹中的JSON文件! - user924

6

CommonsWare先生已经提供了正确的答案,但是XML解析并不像使用简单的解析器那样简单:

public static Map<String, String> getHashMapResource(Context context, int hashMapResId) {
    Map<String, String> map = new HashMap<>();
    XmlResourceParser parser = context.getResources().getXml(hashMapResId);

    String key = null, value = null;

    try {
        int eventType = parser.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                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;
}

1
正如我所写的,正确答案已经由Commonsware提到了,这只是一个补充。我认为在我的回答中再次复制Commonsware的答案是没有用的。 - Christian

0

Android通常使用DefaultsXmlParser.getDefaultsFromXml()来解析下一个语法:

<?xml version="1.0" encoding="utf-8"?>
<defaults>
    <entry>
        <key>api_url</key>
        <value>https://</value>
    </entry>
    <entry>
        <key>some_feature_flag</key>
        <value>true</value>
    </entry>
</defaults>

读取地图:

val map = DefaultsXmlParser.getDefaultsFromXml(this, R.xml.my_map)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接