创建一个地震Viewer

   

接下来的例子,你将要创建一个使用USGS地震种子来显示最近地震列表的工具。

 

你将数次回到这个地震应用程序,第一次是在第6章中的用一个Content Provider保存和共享地震数据,再一次是在第7章和第8章中,添加映射支持和在后台服务中更新地震数据。

 

在这个例子中,你将要创建一个基于ListActivity,它连向一个地震种子,并显示位置、等级以及地震的时间。另外,你还将使用一个AlertDialog来提供一个细节的窗口,包含一个链向USGS站点的可链接TextView

 

1. 创建一个地震工程,包含一个Earthquake Activity。修改main.xml layout资源包含一个ListView控件——确保要命名它,因为在Activity的代码中你要引用它。

 

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

 

2. 创建一个新的Quake公共类。这个类用于储存每个地震的细节(时间,细节,位置,等级和链接等)。重写toString方法来提供在ListView中使用的每个Quake的字符串。

 

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. 在Earthquake Activity里,重写onCreate方法来储存一个Quake对象的ArrayList,并使用一个ArrayAdapter绑定其到ListView上。

 

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;

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. 接下来,处理地震种子。在这个例子中,使用的种子是1天的USGS种子,并且等级大于2.5级。

 

以外部字符串资源的方式添加种子的位置。这种方式的优点是对于不同的用户位置来说可以指定不同的种子。

 

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

 

5. 在你的程序能访问Internet之前,需要授予Internet的权限。在manifest中添加uses-permission节点。

 

<uses-permission xmlns:android=”http://schemas.android.com/apk/res/android”

android:name=”android.permission.INTERNET”>

</uses-permission>

 

6. 回到Earthquake Activity中,创建一个新的refreshEarthquakes方法来连接,解析地震种子。提取每个earthquake,并解析细节来获得时间、等级、链接和位置。当你完成每个earthquake的解析,传递它到新的addNewQuake方法中。

 

XML的解析如下所示,没有太多的解释。

 

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;

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

 

if (nl != null && nl.getLength() > 0)

{

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;

sdf = new SimpleDateFormat(“yyyy-MM-dd’T’hh:mm:ss’Z’”);

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;

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

}

finally

{

}

}

 

private void addNewQuake(Quake _quake) {

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

}

 

7. 更新addNewQuake方法,让它可以带一个刚处理过的Quake参数并将其添加EarthquakeArrayList中。它还应该通知ArrayAdapter底层数据发生了变化。

 

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. 修改onCreate方法在启动时调用refreshEarthquakes

 

@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();

}

 

Internet查询目前发生在UI主线程。这是一种糟糕的方式,当查询需要花费超过几秒的时间时应用程序会变得无响应。在第8章,你将学习如何将这样的耗时的操作移到后台线程中。

 

9. 如果你运行你的工程,你应该看到一个ListView中显示了过去24小时里等级大于2.5的地震,如图5-6所示。

 

5-6

 

10. 还剩下两步来能你的程序变得更加有用。第一,创建一个菜单项来让用户在需要的时候更新一下地址种子。

 

10.1 为菜单选择添加外部字符串。

 

<string name=”menu_update”>Refresh Earthquakes</string>

 

10.2  然后重写ActivityonCreateOptionsMenuonOptionsItemSelected方法,来显示和处理菜单项的更新操作。

 

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. 现在,添加一些用户交互。当用户从地震列表中选择一项时,打开一个对话框,显示更多的地震细节。

 

11.1 创建新的quake_details.xml layout资源,作为用户点击项目时显示的对话框的布局。

 

<?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=”10sp”>

<TextView

android:id=”@+id/quakeDetailsTextView”

android:layout_width=”fill_parent”

android:layout_height=”fill_parent”

android:textSize=”14sp”

/>

</LinearLayout>

 

11.2 然后,修改onCreate方法,为ListView添加一个onItemClickListener,当一个地震项目选择时显示一个对话框。

 

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() {

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 现在,重写onCreateDialogonPrepareDialog方法来创建对话框和填入地震细节。

 

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

sdf = new SimpleDateFormat(“dd/MM/yyyy HH:mm:ss”);

String dateString = sdf.format(selectedQuake.getDate());

String quakeText = “Mangitude “ + 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 最后一步,为对话框制作超链接指向USGS。调整对话框的XML layout资源定义,包含一个autolink特性。

 

<?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=”10sp”>

<TextView

android:id=”@+id/quakeDetailsTextView”

android:layout_width=”fill_parent”

android:layout_height=”fill_parent”

android:textSize=”14sp”

android:autoLink=”all”

/>

</LinearLayout>

 

再次运行你的Activity。当你点击某个地震项目时,一个对话框会显示出来,并使列表部分模糊,如图5-7所示。

 

5-7

 

Sample Code

http://files.cnblogs.com/xirihanlin/DL090804@cc-Earthquake.zip

 

Sample图示:

 

 

转载于:https://www.cnblogs.com/xirihanlin/archive/2009/08/04/1538582.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值