Monday, October 22, 2012

Search WOEID and query Yahoo Weather

In my old posts, demonstrate how to "Search WOEID from http://query.yahooapis.com/" and "Get weather info from Yahoo! Weather RSS Feed". This exercise merge both together.

Search WOEID and query Yahoo Weather

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 from NetworkOnMainThreadException.

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>


download filesDownload the files.

1 comment:

Anonymous said...

Thanks for showing how to get the woeid from a city name! That was exactly what I was looking for!