Creating An Earthquake Viewer

In the following example you'll create a tool that uses a USGS earthquake feed to display a list of recent earthquakes.

You will return to this earthquake application several times, first in Chapters 6 and 7 to save preferences and share the earthquake data with a Content Provider, and again in Chapters 8 and 9 to add mapping support and to move the earthquake updates into a Service.

In this example you'll create a list-based Activitythat connects to an earthquake feed and displays the location, magnitude, and time of the earthquakes it contains. You'll use an Alert Dialog to provide a details window that includes a linkified Text View with a link to the USGS web site.

1. Start by creating an Earthquake project featuring an Earthquake Activity. Modify the main.xml layout resource to include a List View control —be sure to name it so you can reference it from the Activity code.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:id="@+id/earthquakeListView"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

</LinearLayout>

Prepared for ASHLEE KABAT, email: [email protected] Order number: 56760408 This PDF is for the purchaser's personal use in accordance with the Wrox Terms of Service and under US copyright as stated on this book's copyright page. If you did not purchase this copy, please visit www.wrox.com to purchase your own copy.

2. Create a new public Quake class. This class will be used to store the details (date, details, location, magnitude, and link) of each earthquake. Override the toString method to provide the string that will be used to represent each quake in the List View.

package com.paad.earthquake;

import java.util.Date;

import java.text.SimpleDateFormat;

import android.location.Location;

public class Quake { private Date date; private String details; private Location location; private double magnitude; private String link;

public Date getDate() { return date; } public String getDetails() { return details; } public Location getLocation() { return location; } public double getMagnitude() { return magnitude; } public String getLink() { return link; }

public Quake(Date _d, String _det, Location _loc, double _mag, String _link) { date = _d; details = _det; location = _loc; magnitude = _mag; link = _link;

©Override public String toString() {

SimpleDateFormat sdf = new SimpleDateFormat("HH.mm");

String dateString = sdf.format(date);

return dateString + ": " + magnitude + " " + details;

3. In the Earthquake Activity, override the onCreate method to store an ArrayList of Quake objects and bind that to the ListView using an ArrayAdapter:

package com.paad.earthquake;

import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; Prepared for ASHLEE KABAT, email: [email protected] Order number: 56760408 This PDF is for the purchaser's personal use in accordance with the Wrox Terms of Service and under US copyright as stated on this book's copyright page. If you did not purchase this copy, please visit www.wrox.com to purchase your own copy.

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

import android.app.Activity;

import android.app.Dialog;

import android.location.Location;

import android.os.Bundle;

import android.view.Menu;

import android.view.View;

import android.view.WindowManager;

import android.view.MenuItem;

import android.widget.AdapterView;

import android.widget.ArrayAdapter;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.AdapterView.OnItemClickListener;

public class Earthquake extends Activity {

ListView earthquakeListView; ArrayAdapter<Quake> aa;

ArrayList<Quake> earthquakes = new ArrayList<Quake>();

©Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

earthquakeListView = (ListView)this.findViewById(R.id.earthquakeListView);

int layoutID = android.R.layout.simple_list_item_1;

aa = new ArrayAdapter<Quake>(this, layoutID , earthquakes);

earthquakeListView.setAdapter(aa);

4. Next, start processing the earthquake feed. For this example the feed used is the one-day USGS feed for earthquakes with a magnitude greater than 2.5.

Add the location of your feed as an external string resource. This lets you potentially specify a different feed based on a user's location.

<?xml version="1.0" encoding="utf-8"?> <resources>

<string name="app_name">Earthquake</string> <string name="quake_feed">

http://earthquake.usgs.gov/eqcenter/catalogs/1day-M2.5.xml </string> </resources>

Prepared for ASHLEE KABAT, email: [email protected] Order number: 56760408 This PDF is for the purchaser's personal use in accordance with the Wrox Terms of Service and under US copyright as stated on this book's copyright page. If you did not purchase this copy, please visit www.wrox.com to purchase your own copy.

5. Before your application can access the Internet it needs to be granted permission for Internet access. Add the uses-permission to the manifest:

<uses-permission android:name="android.permission.INTERNET"/>

6. Returning to the Earthquake Activity, create a new refreshEarthquakes method that connects to and parses the earthquake feed. Extract each earthquake and parse the details to obtain the date, magnitude, link, and location. As you finish parsing each earthquake, pass it in to a new addNewQuake method.

The earthquake feed XML is parsed here by the SAX parser. Several alternatives exist, including the XmlPullParser. An analysis of the alternative XML parsing techniques (and how to use them) is beyond the scope of this book, but it's important to evaluate and compare the options available within your own applications.

private void refreshEarthquakes() { // Get the XML URL url; try {

String quakeFeed = getString(R.string.quake_feed); url = new URL(quakeFeed);

URLConnection connection; connection = url.openConnection();

HttpURLConnection httpConnection = (HttpURLConnection)connection; int responseCode = httpConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) { InputStream in = httpConnection.getInputStream();

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder();

// Parse the earthquake feed.

Document dom = db.parse(in);

Element docEle = dom.getDocumentElement();

// Clear the old earthquakes earthquakes.clear();

// Get a list of each earthquake entry.

NodeList nl = docEle.getElementsByTagName("entry");

for (int i = 0 ; i < nl.getLength(); i++) { Element entry = (Element)nl.item(i);

Element title = (Element)entry.getElementsByTagName("title").item(0); Element g = (Element)entry.getElementsByTagName("georss:point").item(0) ; Element when = (Element)entry.getElementsByTagName("updated").item(0); Element link = (Element)entry.getElementsByTagName("link").item(0);

String details = title.getFirstChild().getNodeValue();

String hostname = "http://earthquake.usgs.gov";

String linkString = hostname + link.getAttribute("href");

String point = g.getFirstChild().getNodeValue(); String dt = when.getFirstChild().getNodeValue();

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T1hh:mm:ss1Z1"); Date qdate = new GregorianCalendar(0,0,0).getTime(); try {

qdate = sdf.parse(dt); } catch (ParseException e) { e.printStackTrace();

String[] location = point.split(" "); Location l = new Location("dummyGPS"); l.setLatitude(Double.parseDouble(location[0])); l.setLongitude(Double.parseDouble(location[1]));

String magnitudeString = details.split(" ")[1]; int end = magnitudeString.length()-1;

double magnitude = Double.parseDouble(magnitudeString.substring(0, end)); details = details.split(",")[1].trim();

Quake quake = new Quake(qdate, details, l, magnitude, linkString);

// Process a newly found earthquake addNewQuake(quake);

} catch (MalformedURLException e) {

e.printStackTrace(); } catch (IOException e) {

e.printStackTrace(); } catch (ParserConfigurationException e) {

e.printStackTrace(); } catch (SAXException e) { e.printStackTrace();

private void addNewQuake(Quake _quake) {

// TODO: Add the earthquakes to the array list.

7. Update the addNewQuake method so that it takes each newly processed quake and adds it to the earthquake Array List. It should also notify the Array Adapter that the underlying data has changed.

private void addNewQuake(Quake _quake) {

// Add the new quake to our list of earthquakes. earthquakes.add(_quake);

// Notify the array adapter of a change. aa.notifyDataSetChanged();

8. Modify your onCreate method to call refreshEarthquakes on startup: ©Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

earthquakeListView = (ListView)this.findViewById(R.id.earthquakeListView);

int layoutID = android.R.layout.simple_list_item_1;

aa = new ArrayAdapter<Quake>(this, layoutID , earthquakes);

earthquakeListView.setAdapter(aa);

refreshEarthquakes();

The Internet lookup is currently happening on the main UI thread. This is bad form, as the application will become unresponsive if the lookup takes longer than a few seconds. In Chapter 9 you'll learn how to move expensive or time-consuming operations like this into a Service and onto a background thread.

9. If you run your project, you should see a List

View that features the earthquakes from the last 24 hours with a magnitude greater than 2.5, as shown in the screen shot in Figure 5-6.

10. There are two more steps needed to make this a more useful application. First, create a new Menu Item to let users refresh the earthquake feed on demand.

10.1. Start by adding a new external string for the menu option:

<string name="menu_update">

Refresh Earthquakes </string>

10.2. Then override the Activity'onCreate OptionsMenu and onOptionsItem Selected methods to display and handle the Refresh Earthquakes Menu Item:

Earthquake ui.ü; 1 virgin isianas region

02.46: 3.1 Central Alaska

00.09: 4.7 Babuyan Islands region

19.50: 3.0 Virgin Islands region 19.30: 3.0 Central Alaska 15.20: 4.6 Banda Sea 11.36: 4.8 Jujuy

FIGURE 5-6

static final private int MENU_UPDATE = Menu.FIRST; ©Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu);

menu.add(0, MENU_UPDATE, Menu.NONE, R.string.menu_update); return true;

©Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item);

switch (item.getItemId()) { case (MENU_UPDATE): { refreshEarthquakes(); return true;

return false;

11. Now add some interaction. Let users find more details by opening a dialog box when they select an earthquake from the list.

11.1. Create a new quake_details.xml layout resource for the dialog box you'll display when an item is clicked:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp"> <TextView android:id="©+id/quakeDetailsTextView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:textSize="14sp"

</LinearLayout>

11.2. Then modify your onCreate method to add an ItemClickListener to the List View that displays a dialog box whenever an earthquake item is clicked:

static final private int QUAKE_DIALOG = 1; Quake selectedQuake;

©Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

earthquakeListView = (ListView)this.findViewById(R.id.earthquakeListView);

earthquakeListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView _av, View _v, int _index, long arg3) { selectedQuake = earthquakes.get(_index); showDialog(QUAKE_DIALOG);

int layoutID = android.R.layout.simple_list_item_1;

aa = new ArrayAdapter<Quake>(this, layoutID , earthquakes);

earthquakeListView.setAdapter(aa);

refreshEarthquakes();

11.3. Now override the onCreateDialog and onPrepareDialog methods to create and populate the earthquake details dialog box:

@Override public Dialog onCreateDialog(int id) { switch(id) {

case (QUAKE_DIALOG) :

LayoutInflater li = LayoutInflater.from(this);

View quakeDetailsView = li.inflate(R.layout.quake_details, null);

AlertDialog.Builder quakeDialog = new AlertDialog.Builder(this); quakeDialog.setTitle("Quake Time"); quakeDialog.setView(quakeDetailsView); return quakeDialog.create();

return null;

@Override public void onPrepareDialog(int id, Dialog dialog) { switch(id) {

case (QUAKE_DIALOG) :

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); String dateString = sdf.format(selectedQuake.getDate()); String quakeText = "Magnitude " + selectedQuake.getMagnitude() + "\n" + selectedQuake.getDetails() + "\n" + selectedQuake.getLink();

AlertDialog quakeDialog = (AlertDialog)dialog;

quakeDialog.setTitle(dateString);

TextView tv = (TextView)quakeDialog.findViewById

(R.id.quakeDetailsTextView); tv.setText(quakeText);

break;

11.4. The final step is to linkify the dialog to make the link to the USGS a hyperlink.

Adjust the dialog box's XML layout resource definition to include amutolink attribute:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp"> <TextView android:id="@+id/quakeDetailsTextView"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:textSize="14sp"

android:autoLink="all"

</LinearLayout>

All code snippets in this example are part of the Chapter 5 Earthquake project, available for download at Wrox.com.

Launch your application again. When you click a particular earthquake a dialog will appear, partially obscuring the list, as shown in Figure 5-7.

Mobile Apps Made Easy

Mobile Apps Made Easy

Quick start guide to skyrocket your offline and online business success with mobile apps. If you know anything about mobile devices, you’ve probably heard that famous phrase coined by one of the mobile device’s most prolific creators proclaiming that there’s an app for pretty much everything.

Get My Free Training Guide


Responses

  • piia-noora
    What is earthquake listview?
    7 years ago

Post a comment