Thursday 13 November 2008

Getting USGS Earthquake Data into Android

This is the second instalment on how to display USGS Earthquake data on Android. The last post dealt with displaying the data, this post with getting it.

Here we use the USGS RSS feed containing the last day or so of earthquakes, which is available here. This is a standard XML document, which I decided to parse and store in a content provider, which hides a SQLite Database. I do not show the content provider here, but it stores some text, the magnitude and the location. I decided not to update the database, but to wipe it clean every time. While it is possible to add to existing earthquake data, care must be taken, because the USGS updates data on earthquakes it has reported on earlier, so for some quakes an insert is required, for others an update. Here I want to get only the latest data, so I can afford to wipe the data.

I decided to implement it as a service that schedules a task using the Java Timer class. My runnable gets the feed, parses it and builds up info on the earthquakes. This is then, in a separate step, inserted into the database, where it is picked up from the Overlay as explained in the last post. The parser is simply a SAX parser that implements a little state machine and accumulates all the earthquake info from the feed (some questions to USGS: why not put magnitude and time stamp into a more readable format in their own elements? I am pretty sure most people want this.)

The schedule task looks like this:

private class Task extends TimerTask {
URL url;
SAXParser sp;
XMLReader xmlReader;
USGSHandler handler;
public Task() {
handler = new USGSHandler();
try {
url = new URL("http://earthquake.usgs.gov/eqcenter/catalogs/1day-M2.5.xml");
SAXParserFactory spf = SAXParserFactory.newInstance();
sp = spf.newSAXParser();
xmlReader = sp.getXMLReader();
xmlReader.setContentHandler(handler);
xmlReader.setErrorHandler(handler);
} catch (IOException e){
Log.e(TAG, e.toString());
} catch (SAXException e){
Log.e(TAG, e.toString());
} catch (ParserConfigurationException e){
Log.e(TAG, e.toString());
}
}
@Override
public void run() {
Log.e(TAG, "refreshing earthquakes");
handler.reset();
try {
xmlReader.parse(new InputSource(url.openStream()));
} catch (IOException e) {
Log.e(TAG, e.toString());
} catch (SAXException e) {
Log.e(TAG, e.toString());
}
List quakes = handler.getQuakes();
getContentResolver().delete(EarthquakeContentProvider.EarthquakeData.CONTENT_URI, "1 = 1", null);
for (Earthquake e : quakes){
ContentValues values = new ContentValues();
values.put(EarthquakeContentProvider.EarthquakeData.TEXT, e.mText);
values.put(EarthquakeContentProvider.EarthquakeData.LON, Math.round(e.mLon * 1.e6));
values.put(EarthquakeContentProvider.EarthquakeData.LAT, Math.round(e.mLat * 1e6));
values.put(EarthquakeContentProvider.EarthquakeData.MAGNITUDE, e.mMagnitude);
getContentResolver().insert(EarthquakeContentProvider.EarthquakeData.CONTENT_URI, values);

}
}

}

As usual lousy error handling.

No comments: