Tuesday, March 12, 2013

Get weather info from Yahoo! Weather RSS Feed in background thread

It's updated version of the exercise "Get weather info from Yahoo! Weather RSS Feed". In the original exercise, the Yahoo Weather is get in UI thread, "android.os.NetworkOnMainThreadException" will be thrown. In order to prevent it, we can move the network related code into a Thread. And after finished, update UI inside a Runnable object passed to runOnUiThread() method.

Get weather info from Yahoo! Weather RSS Feed in background thread


package com.example.androidyahooweatherdom;

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.Node;
import org.xml.sax.SAXException;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity 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(){
   
   return "\n- " + 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";
   
  } 
 }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        weather = (TextView)findViewById(R.id.weather);

        Thread myThread = new Thread(new Runnable(){

   @Override
   public void run() {
    String weatherString = QueryYahooWeather();
          Document weatherDoc = convertStringToDocument(weatherString);
          
          final MyWeather weatherResult = parseWeather(weatherDoc);
          runOnUiThread(new Runnable(){

     @Override
     public void run() {
      weather.setText(weatherResult.toString());
     }});
          
   }});
        myThread.start();
    }
    
    private MyWeather parseWeather(Document srcDoc){
     
     MyWeather myWeather = new MyWeather();

     //<description>Yahoo! Weather for New York, NY</description>
     myWeather.description = srcDoc.getElementsByTagName("description")
       .item(0)
       .getTextContent();

     //<yweather:location.../>
     Node locationNode = srcDoc.getElementsByTagName("yweather:location").item(0);
     myWeather.city = locationNode.getAttributes()
       .getNamedItem("city")
       .getNodeValue()
       .toString();
     myWeather.region = locationNode.getAttributes()
       .getNamedItem("region")
       .getNodeValue()
       .toString();
     myWeather.country = locationNode.getAttributes()
       .getNamedItem("country")
       .getNodeValue()
       .toString();

     //<yweather:wind.../>
     Node windNode = srcDoc.getElementsByTagName("yweather:wind").item(0);
     myWeather.windChill = windNode.getAttributes()
       .getNamedItem("chill")
       .getNodeValue()
       .toString();
     myWeather.windDirection = windNode.getAttributes()
       .getNamedItem("direction")
       .getNodeValue()
       .toString();
     myWeather.windSpeed = windNode.getAttributes()
       .getNamedItem("speed")
       .getNodeValue()
       .toString();

     //<yweather:astronomy.../>
     Node astronomyNode = srcDoc.getElementsByTagName("yweather:astronomy").item(0);
     myWeather.sunrise = astronomyNode.getAttributes()
       .getNamedItem("sunrise")
       .getNodeValue()
       .toString();
     myWeather.sunset = astronomyNode.getAttributes()
       .getNamedItem("sunset")
       .getNodeValue()
       .toString();

     //<yweather:condition.../>
     Node conditionNode = srcDoc.getElementsByTagName("yweather:condition").item(0);
     myWeather.conditiontext = conditionNode.getAttributes()
       .getNamedItem("text")
       .getNodeValue()
       .toString();
     myWeather.conditiondate = conditionNode.getAttributes()
       .getNamedItem("date")
       .getNodeValue()
       .toString();

     return myWeather; 
    }
    
    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();
      Toast.makeText(MainActivity.this,
        e1.toString(), Toast.LENGTH_LONG).show(); 
     } catch (SAXException e) {
      e.printStackTrace();
      Toast.makeText(MainActivity.this,
        e.toString(), Toast.LENGTH_LONG).show(); 
     } catch (IOException e) {
      e.printStackTrace();
      Toast.makeText(MainActivity.this,
        e.toString(), Toast.LENGTH_LONG).show(); 
     }
     
     return dest; 
    }

    private String QueryYahooWeather(){
     
     String qResult = "";
     String queryString = "http://weather.yahooapis.com/forecastrss?w=2459115";
     
     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();
      Toast.makeText(MainActivity.this,
        e.toString(), Toast.LENGTH_LONG).show(); 
     } catch (IOException e) {
      e.printStackTrace();
      Toast.makeText(MainActivity.this,
        e.toString(), Toast.LENGTH_LONG).show(); 
     }
     
     return qResult; 
    }
    
}


<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"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <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>


You have to modify AndroidManifest.xml to grand permission of "android.permission.INTERNET"

download filesDownload the files.

Next:
- Get yweather:forecast from Yahoo! Weather RSS Feed


2 comments:

Manchester said...

thanks for useful tutorial but i wanna know how i can got weather for current location or by list view search ....

Erik said...

hello Manchester,

you have to search WOEID for your location.

Please read my old post: http://android-er.blogspot.com/2012/03/get-weather-info-from-yahoo-weather-rss.html. Links in the bottom of the post.