Android resource files are a great way to keep your data separate from your code. It works great as long, as all you need is one of the supported types. What do you do if you have a more complex static data type that you’d like to manage independently of the code?
The answer is to create a ‘raw’ XML file under the /res/xml directory and write the parser logic yourself. For example, let’s say you want to compare the elevation of the mountains in your state. As mountains tend to stick around a while, there is no reason to query a database every time you want an elevation. Instead, you can simply create a static XML file like so:
/res/xml/mountain_data.xml
<?xml version="1.0" encoding="utf-8"?> <mountains> <mountain name="Mt. Elbert" county="Lake" elevation="14433" lat="39.11807" long="-106.445417" range="Sawatch" rank="1" /> <mountain name="Mt. Massive" county="Lake" elevation="14421" lat="39.187298" long="-106.475548" range="Sawatch" rank="2" /> <mountain name="Mt. Harvard" county="Chaffee" elevation="14420" lat="38.924328" long="-106.320618" range="Sawatch" rank="3" /> </mountains>
Custom resource types don’t get fully precompiled into the ‘R’ class, and hence, you need to load and parse them yourself. At runtime simply load the file using
Resources.getXML(R.fileId) and then parse the data using XmlResourceParser. This parser is very basic and steps through each element every time you call
next(). With each element you can call getEventType() to determine if its a close or open tag. The following code will load, parse and store the elevation
of each mountain in the resource file into a list.
List<String> elevations = new ArrayList<String>(); Resources res = getResources(); XmlResourceParser xrp = res.getXml(R.xml.mountain_data); try{ xrp.next(); // skip first 'mountains' element while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) { xrp.next(); // get first 'mountain' element if(xrp.getEventType() == XmlResourceParser.START_TAG) { // double check its the right element if(xrp.getName().equals("mountain")) { // extract the data you want int count = xrp.getAttributeCount(); String name = xrp.getAttributeValue(null, "name"); String elev = xrp.getAttributeValue(null, "elevation"); // add elevation to the list elevations.add(elev); Log.v(TAG, "Attribute Count " + count); Log.v(TAG, "Peak Name " + name); } } } } catch (Exception e) { Log.w(TAG, e.toString()); } finally { xrp.close(); Log.i(TAG, elevations.toString()); }
Doing this allows you to shrink or expanded the number of mountains without impacting or touching any code.