TypeArray in Android - How to store custom objects in xml and retrieve them?

Ishan picture Ishan · Jul 21, 2011 · Viewed 22.4k times · Source

I have a class like

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

and want to store objects of this class in an TypeArray xml of android like

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

how i want to access this array in my Activty class like

TypedArray customArr = getResources().obtainTypedArray(R.array.country_arr);
    CountryV) 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**);

But i don't to how to achieve this. I tried customArr.getString(0); but it gives me everything as string like Albania al @drawable/al

Please help me to solve this problem.

Thanks a lot in advance,

With best regards, Ishan

Answer

pablisco picture pablisco · Mar 21, 2012

When I need custom objects that can be edited outside code i generally use json which is easier to read for both humans and (possibly) machines ;)

You can also have more complex objects than with simple arrays.

Once you create a json file (e.g. countries.json) in the /res/raw folder like this:

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

you can load the data like this:

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

If you don't want to do the parsing manually you can also use gson which helps you to pass the objects and then load the drawables in a lazy fashion... ;)

Edit: Added utility class

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

Hope it helps