在Android中的TypeArray - 如何将自定义对象存储在xml中并检索它们?

22

我有一个类似这样的类:

public class CountryVO {
    private String countryCode;
    private String countryName;
    private Drawable countryFlag;
    
    public String getCountryCode() {
        return countryCode;
    }
    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }
    public String getCountryName() {
        return countryName;
    }
    public void setCountryName(String countryName) {
        this.countryName = countryName;
    }
    public Drawable getCountryFlag() {
        return countryFlag;
    }
    public void setCountryFlag(Drawable countryFlag) {
        this.countryFlag = countryFlag;
    }
}

我想将这个类的对象存储在 Android 的 TypeArray xml 中,例如:

<resources>
    <array name="custom_arr">
        <item>
            <countryName>Albania</countryName>
            <countryCode>al</countryCode>
            <countryFlag>@drawable/al</countryFlag>
        </item>
        <item>
            <countryName>Algeria</countryName>
            <countryCode>dz</countryCode>
            <countryFlag>@drawable/dz</countryFlag>
        </item>
        <item>
            <countryName>American Samoa</countryName>
            <countryCode>as</countryCode>
            <countryFlag>@drawable/as</countryFlag>
        </item>
        <item>
            <countryName>India</countryName>
            <countryCode>in</countryCode>
            <countryFlag>@drawable/in</countryFlag>
        </item>
        <item>
            <countryName>South Africa</countryName>
            <countryCode>sa</countryCode>
            <countryFlag>@drawable/sa</countryFlag>
        </item>
    </array>
</resources>

我想在我的Activity类中访问这个数组,应该怎么做?

TypedArray customArr = getResources().obtainTypedArray(R.array.country_arr);
    CountryVO vo = new CountryVO();
    vo.setCountryName(**value from array come here for first element's countryName attribute**);
    vo.setCountryCode(**value from array come here for first element's countryCode attribute**);
    vo.setCountryFlag(**value from array come here for first element's countryFlag attribute**);

但我不知道如何实现这一点。 我尝试了customArr.getString(0);但它给了我一个字符串,类似于 阿尔巴尼亚 al @drawable/al

请帮我解决这个问题。

非常感谢您的帮助,

致以最诚挚的问候, Ishan

3个回答

16

当我需要使用可在代码外部进行编辑的自定义对象时,通常使用 JSON,因为它对于人和(可能)机器来说都更易读;)

您还可以拥有比简单数组更复杂的对象。

一旦您在/res/raw文件夹中创建了这样一个 JSON 文件(例如 countries.json):

{ "countries" : [
    {"country" : "Albania", "countryCode" : "al" },
    {"country" : "Algeria", "countryCode" : "dz"},
    {"country" : "American Samoa", "countryCode" : "as"},
    {"country" : "India", "countryCode" : "in"},
    {"country" : "South Africa", "countryCode" : "sa"}
]}

你可以像这样加载数据:

InputStream jsonStream = context.getResources().openRawResource(R.raw.countries);
JSONObject jsonObject = new JSONObject(Strings.convertStreamToString(jsonStream));
JSONArray jsonContries = jsonObject.getJSONArray("countries");
List<CountryVO> countries = new ArrayList<CountryVO>();
for (int i = 0, m = countries.length(); i < m; i++) {
    JSONObject jsonCountry = countries.getJSONObject(i);
    CountryVO country = new CountryVO();
    country.setCountryName(jsonCountry.getString("country"));
    String co = jsonCountry.getString("countryCode");
    country.setCountryCode(co);
    try {
        Class<?> drawableClass = com.example.R.drawable.class; // replace package
        Field drawableField = drawableClass.getField(co);
        int drawableId = (Integer)drawableField.get(null);
        Drawable drawable = getResources().getDrawable(drawableId);
        country.setCountryFlag(drawable);
     } catch (Exception e) {
         // report exception
     }
     countries.add(country);
}
如果您不想手动解析,也可以使用Gson,它可以帮助您传递对象并以一种懒加载的方式加载图形... ;)

编辑:添加了实用程序类。

public String convertStreamToString(InputStream is) { 
  Scanner s = new Scanner(is).useDelimiter("\\A");
  return s.hasNext() ? s.next() : "";
}

希望能帮到你


我遇到了一个错误 无法解析方法 convertStreamToString。我尝试导入所有可用选项。 - wick.ed
非常正确。我忘了。这是一个实用类。我会尝试找到代码的。虽然功能是将流的输出复制到新字符串中,但已经有解决方案了。 - pablisco
另外,如果您可以使用Gson,我会推荐它。减少低级别的代码。 - pablisco
是的,我最终用另一种方式完成了它。谢谢 :) - wick.ed

16

这里有一个例子。阅读它并查看TypedArray的方法,例如getDrawable(int index)中的get...()。我建议将相同类型的项目保留在不同的数组中。

<array name="country">
    <item>Albania</item>
    <item>Algeria</item>
    <item>American Samoa</item>
</array>
<array name="code">
    <item>al</item>
    <item>dz</item>
    <item>as</item>
</array>
<array name="flag">
    <item>@drawable/dz</item>
    <item>@drawable/al</item>
    <item>@drawable/as</item>
</array>

EDIT:

public CountryVO getCountryVO(int index){
    Resources resources = getResources();
    TypedArray country = resources.obtainTypedArray(R.array.country);
    TypedArray code = resources.obtainTypedArray(R.array.code);
    TypedArray flag = resources.obtainTypedArray(R.array.flag);

    CountryVO vo = new CountryVO(country.getString(index), code.getString(index), flag.getDrawable(index));

    country.recycle();
    code.recycle();
    flag.recycle();

    return vo;
}

谢谢Dziobas的回复。实际上我已经这样做了,并创建了三个不同的数组,但它看起来很奇怪,所以我正在寻找一种方法,在单个xml中存储所有数据。而且,我想要做的不是使用getDrawable(int index),而是使用getCountryVO(int index)。有没有办法实现这个? - Ishan
你可以在 getCountryVO(int index) 中实现它,只需将获取国家、代码和旗帜的代码放入数组中即可。 - pawelzieba
但是在调用getResources().obtainTypedArray("array_name")时,无法直接使用getResources().obtainTypedArray("array_name").getCountryVO(index)。请问您能否指导我如何从TypedArray中获取特定索引处的对象? - Ishan
1
你好,谢谢!你在新的CountryVO中提供了一个不错的解决方案。但是你知道这有两个缺点,请纠正我如果我错了。1.我们需要管理3个不同的xml文件,这很困难且容易出错。2.为了创建一个对象,需要在CountryVO中获取这3个数组,从内存管理的角度来看,这似乎有些奇怪。这就是为什么我想把所有这些信息都放在一个数组中进行管理。目前我采用另一种解决方案,即创建一个Map并将所有的CountryVO放入其中。 - Ishan
我刚刚回答了你的问题。就像我提供的链接中所述,它在一个XML文件中。我不确定,但是资源中的XML是内置于应用程序二进制文件中的,因此可能会被编译器优化。这应该比使用SAX解析更快。当然,你也可以将其放入Java类的静态数组中。我不知道你有什么要求。祝你好运。 - pawelzieba

0

在尝试将xml存储到类中之前,您需要解析它。我建议您使用SAX API,您可以在这里找到有关其的教程。希望这可以帮到您!


嗨Kenny,谢谢你的回复,但我们不能通过使用android xml和getResources().obtailtypearray()方法来解决这个问题吗?直接解析xml会增加我的应用程序的工作量。 - Ishan

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