Android-er: Search WOEID and query Yahoo Weather
因為Google停止了iGoogle的服務,也停止了Google Weather Api的服務,因為沒有好用的Google提供的天氣Api只好找尋其他的天氣服務。
首先利用Yahoo提供的API將城市名轉換為WOEID,再利用WOEID取得Yahoo Weather API中所提供的天氣訊息,詳情請參考連結。
不過目前對於web的存取及解析還不太了解,這些等之後有更進一步的研究之後,再來好好回過頭來分析這支程式在寫啥吧
另外改天在把修改後的source code貼上~~~
User enter location to be searched for WOEID, then clicked the WOEID to start another activity querying Yahoo for the weather.
And also, the code to read from internet have been moved to AsyncTask to prevent fromNetworkOnMainThreadException.
Main activity, MainActivity.java.
package com.example.androidwoeidweather;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Intent;
public class MainActivity extends Activity {
//Example for "New York"
//http://query.yahooapis.com/v1/public/yql?q=select*from geo.places where text="New York"&format=xml
final String yahooPlaceApisBase = "http://query.yahooapis.com/v1/public/yql?q=select*from%20geo.places%20where%20text=";
final String yahooapisFormat = "&format=xml";
String yahooPlaceAPIsQuery;
EditText place;
Button search;
ListView listviewWOEID;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
place = (EditText)findViewById(R.id.place);
search = (Button)findViewById(R.id.search);
listviewWOEID = (ListView)findViewById(R.id.woeidlist);
search.setOnClickListener(searchOnClickListener);
}
Button.OnClickListener searchOnClickListener
= new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
if(place.getText().toString().equals("")){
Toast.makeText(getBaseContext(),
"Enter place!",
Toast.LENGTH_LONG).show();
}else{
new MyQueryYahooPlaceTask().execute();
}
}
};
private class MyQueryYahooPlaceTask extends AsyncTask<Void, Void, Void>{
ArrayList<String> l;
@Override
protected Void doInBackground(Void... arg0) {
l = QueryYahooPlaceAPIs();
return null;
}
@Override
protected void onPostExecute(Void result) {
ArrayAdapter<String> aa = new ArrayAdapter<String>(
getBaseContext(), android.R.layout.simple_list_item_1, l);
listviewWOEID.setAdapter(aa);
listviewWOEID.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
String selWoeid = parent.getItemAtPosition(position).toString();
/*
Toast.makeText(getApplicationContext(),
selWoeid,
Toast.LENGTH_LONG).show();
*/
Intent intent = new Intent();
intent.setClass(MainActivity.this, GetWeather.class);
Bundle bundle = new Bundle();
bundle.putCharSequence("SEL_WOEID", selWoeid);
intent.putExtras(bundle);
startActivity(intent);
}});
super.onPostExecute(result);
}
}
private ArrayList<String> QueryYahooPlaceAPIs(){
String uriPlace = Uri.encode(place.getText().toString());
yahooPlaceAPIsQuery = yahooPlaceApisBase
+ "%22" + uriPlace + "%22"
+ yahooapisFormat;
String woeidString = QueryYahooWeather(yahooPlaceAPIsQuery);
Document woeidDoc = convertStringToDocument(woeidString);
return parseWOEID(woeidDoc);
}
private ArrayList<String> parseWOEID(Document srcDoc){
ArrayList<String> listWOEID = new ArrayList<String>();
NodeList nodeListDescription = srcDoc.getElementsByTagName("woeid");
if(nodeListDescription.getLength()>=0){
for(int i=0; i<nodeListDescription.getLength(); i++){
listWOEID.add(nodeListDescription.item(i).getTextContent());
}
}else{
listWOEID.clear();
}
return listWOEID;
}
private Document convertStringToDocument(String src){
Document dest = null;
DocumentBuilderFactory dbFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder parser;
try {
parser = dbFactory.newDocumentBuilder();
dest = parser.parse(new ByteArrayInputStream(src.getBytes()));
} catch (ParserConfigurationException e1) {
e1.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return dest;
}
private String QueryYahooWeather(String queryString){
String qResult = "";
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(queryString);
try {
HttpEntity httpEntity = httpClient.execute(httpGet).getEntity();
if (httpEntity != null){
InputStream inputStream = httpEntity.getContent();
Reader in = new InputStreamReader(inputStream);
BufferedReader bufferedreader = new BufferedReader(in);
StringBuilder stringBuilder = new StringBuilder();
String stringReadLine = null;
while ((stringReadLine = bufferedreader.readLine()) != null) {
stringBuilder.append(stringReadLine + "\n");
}
qResult = stringBuilder.toString();
}
} catch (ClientProtocolException e) {
e.printStackTrace();;
} catch (IOException e) {
e.printStackTrace();
}
return qResult;
}
}
Layout of the main activity, activity_main.xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<EditText
android:id="@+id/place"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/search"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Search WOEID by place" />
<ListView
android:id="@+id/woeidlist"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
The activity to query weather from Yahoo, GetWeather.java.
package com.example.androidwoeidweather;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
public class GetWeather extends Activity {
TextView weather;
class MyWeather{
String description;
String city;
String region;
String country;
String windChill;
String windDirection;
String windSpeed;
String sunrise;
String sunset;
String conditiontext;
String conditiondate;
public String toString(){
String s;
s = description + " -\n\n" + "city: " + city + "\n"
+ "region: " + region + "\n"
+ "country: " + country + "\n\n"
+ "Wind\n"
+ "chill: " + windChill + "\n"
+ "direction: " + windDirection + "\n"
+ "speed: " + windSpeed + "\n\n"
+ "Sunrise: " + sunrise + "\n"
+ "Sunset: " + sunset + "\n\n"
+ "Condition: " + conditiontext + "\n"
+ conditiondate +"\n";
return s;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_weather);
weather = (TextView)findViewById(R.id.weather);
Bundle bundle = this.getIntent().getExtras();
String sel_woeid = (String)bundle.getCharSequence("SEL_WOEID");
new MyQueryYahooWeatherTask(sel_woeid).execute();
Toast.makeText(getApplicationContext(),
sel_woeid,
Toast.LENGTH_LONG).show();
}
private class MyQueryYahooWeatherTask extends AsyncTask<Void, Void, Void>{
String woeid;
String weatherResult;
String weatherString;
MyQueryYahooWeatherTask(String w){
woeid = w;
}
@Override
protected Void doInBackground(Void... arg0) {
weatherString = QueryYahooWeather();
Document weatherDoc = convertStringToDocument(weatherString);
if(weatherDoc != null){
weatherResult = parseWeather(weatherDoc).toString();
}else{
weatherResult = "Cannot convertStringToDocument!";
}
return null;
}
@Override
protected void onPostExecute(Void result) {
weather.setText(weatherResult);
super.onPostExecute(result);
}
private String QueryYahooWeather(){
String qResult = "";
String queryString = "http://weather.yahooapis.com/forecastrss?w=" + woeid;
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(queryString);
try {
HttpEntity httpEntity = httpClient.execute(httpGet).getEntity();
if (httpEntity != null){
InputStream inputStream = httpEntity.getContent();
Reader in = new InputStreamReader(inputStream);
BufferedReader bufferedreader = new BufferedReader(in);
StringBuilder stringBuilder = new StringBuilder();
String stringReadLine = null;
while ((stringReadLine = bufferedreader.readLine()) != null) {
stringBuilder.append(stringReadLine + "\n");
}
qResult = stringBuilder.toString();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return qResult;
}
private Document convertStringToDocument(String src){
Document dest = null;
DocumentBuilderFactory dbFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder parser;
try {
parser = dbFactory.newDocumentBuilder();
dest = parser.parse(new ByteArrayInputStream(src.getBytes()));
} catch (ParserConfigurationException e1) {
e1.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return dest;
}
private MyWeather parseWeather(Document srcDoc){
MyWeather myWeather = new MyWeather();
//<description>Yahoo! Weather for New York, NY</description>
NodeList descNodelist = srcDoc.getElementsByTagName("description");
if(descNodelist != null && descNodelist.getLength() > 0){
myWeather.description = descNodelist.item(0).getTextContent();
}else{
myWeather.description = "EMPTY";
}
//<yweather:location city="New York" region="NY" country="United States"/>
NodeList locationNodeList = srcDoc.getElementsByTagName("yweather:location");
if(locationNodeList != null && locationNodeList.getLength() > 0){
Node locationNode = locationNodeList.item(0);
NamedNodeMap locNamedNodeMap = locationNode.getAttributes();
myWeather.city = locNamedNodeMap.getNamedItem("city").getNodeValue().toString();
myWeather.region = locNamedNodeMap.getNamedItem("region").getNodeValue().toString();
myWeather.country = locNamedNodeMap.getNamedItem("country").getNodeValue().toString();
}else{
myWeather.city = "EMPTY";
myWeather.region = "EMPTY";
myWeather.country = "EMPTY";
}
//<yweather:wind chill="60" direction="0" speed="0"/>
NodeList windNodeList = srcDoc.getElementsByTagName("yweather:wind");
if(windNodeList != null && windNodeList.getLength() > 0){
Node windNode = windNodeList.item(0);
NamedNodeMap windNamedNodeMap = windNode.getAttributes();
myWeather.windChill = windNamedNodeMap.getNamedItem("chill").getNodeValue().toString();
myWeather.windDirection = windNamedNodeMap.getNamedItem("direction").getNodeValue().toString();
myWeather.windSpeed = windNamedNodeMap.getNamedItem("speed").getNodeValue().toString();
}else{
myWeather.windChill = "EMPTY";
myWeather.windDirection = "EMPTY";
myWeather.windSpeed = "EMPTY";
}
//<yweather:astronomy sunrise="6:52 am" sunset="7:10 pm"/>
NodeList astNodeList = srcDoc.getElementsByTagName("yweather:astronomy");
if(astNodeList != null && astNodeList.getLength() > 0){
Node astNode = astNodeList.item(0);
NamedNodeMap astNamedNodeMap = astNode.getAttributes();
myWeather.sunrise = astNamedNodeMap.getNamedItem("sunrise").getNodeValue().toString();
myWeather.sunset = astNamedNodeMap.getNamedItem("sunset").getNodeValue().toString();
}else{
myWeather.sunrise = "EMPTY";
myWeather.sunset = "EMPTY";
}
//<yweather:condition text="Fair" code="33" temp="60" date="Fri, 23 Mar 2012 8:49 pm EDT"/>
NodeList conditionNodeList = srcDoc.getElementsByTagName("yweather:condition");
if(conditionNodeList != null && conditionNodeList.getLength() > 0){
Node conditionNode = conditionNodeList.item(0);
NamedNodeMap conditionNamedNodeMap = conditionNode.getAttributes();
myWeather.conditiontext = conditionNamedNodeMap.getNamedItem("text").getNodeValue().toString();
myWeather.conditiondate = conditionNamedNodeMap.getNamedItem("date").getNodeValue().toString();
}else{
myWeather.conditiontext = "EMPTY";
myWeather.conditiondate = "EMPTY";
}
return myWeather;
}
}
}
Layout of GetWeather, layout_weather.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/weather"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
Modify AndroidManifest.xml to add activity ".GetWeather" and permission of "android.permission.INTERNET".
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidwoeidweather"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".GetWeather">
</activity>
</application>
</manifest>