Ever needed to embed a configuration file in your Android app? What’s the best practice? As far as I know, there isn’t one. Here’s a nice solution. What’d you’d like is to be able to define your configuration in the same format as an Android resource file, like this,
<string name="url">http://www.foo.com</string>
You can put your resource in strings.xml (or any other file in res/values), but then you are stuck with completions. Do you want R.string.url to be a valid string resource in your app? No, it’s not a localizable string and having it respond to code completion isn’t the right thing. Moreover, if you are providing a library, you will expose your configuration values to developers that import your library.
You can put an XML resource file in res/xml, but Android isn’t going to parse it. Here’s a simple helper class to parse a a res/xml resource as an Android resource file,
public class XmlResourceParser { protected final Context context; private final Map<String, String> strings = new HashMap<String, String>(); private final Map<String, Integer> integers = new HashMap<String, Integer>(); private final Map<String, Boolean> booleans = new HashMap<String, Boolean>(); public XmlResourceParser(Context context) { this.context = context; } public void parse(int id) throws XmlPullParserException, IOException { XmlPullParser xpp = context.getResources().getXml(id); int eventType = xpp.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_DOCUMENT) { } else if (eventType == XmlPullParser.START_TAG) { String tag = xpp.getName(); if ("string".equals(tag)) { strings.put(xpp.getAttributeValue(null, "name"), xpp.nextText()); } else if ("integer".equals(tag)) { integers.put(xpp.getAttributeValue(null, "name"), Integer.valueOf(xpp.nextText())); } else if ("boolean".equals(tag)) { booleans.put(xpp.getAttributeValue(null, "name"), Boolean.valueOf(xpp.nextText())); } } else if (eventType == XmlPullParser.END_TAG) { } else if (eventType == XmlPullParser.TEXT) { } eventType = xpp.next(); } } public String getString(String key, String def) { if (strings.containsKey(key)) { return strings.get(key); } return def; } public int getInt(String key, int def) { if (integers.containsKey(key)) { return integers.get(key); } return def; } public boolean getBoolean(String key, boolean def) { if (booleans.containsKey(key)) { return booleans.get(key); } return def; } }
Obviously this only handles strings, ints, and bools. The rest is left for an exercise for the reader. You use it like this,
XmlResourceParser xrp = new XmlResourceParser().parse(R.xml.myresources); String url = xrp.getString("url");