Wednesday, March 28, 2012

Google Weather App

Last exercise demonstrate the basic of Google Weather API. It's modified to be a completed app with better look, with function of searching place.

Google Weather App

Main Java code:
package com.exercise.AndroidGoogleWeather;

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.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

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.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidGoogleWeatherActivity extends Activity {

class ForecastInformation{
String city;
String postal_code;
String forecast_date;
String current_date_time;
String unit_system;
}

class CurrentConditions{
String condition;
String temp_f;
String temp_c;
String humidity;
String icon;
String wind_condition;
}

class ForecastConditions{
String day_of_week;
String low;
String high;
String icon;
String condition;
}

ForecastInformation forecastInformation;
CurrentConditions currentConditions;
List<ForecastConditions> forecastConditionsList;

Button buttonEnter;
EditText edittextPlace;
ImageView iconCurrent;
TextView textCurrent;
TextView textInfo;
ListView listForcast;


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

buttonEnter = (Button)findViewById(R.id.enter);
edittextPlace = (EditText)findViewById(R.id.place);
iconCurrent = (ImageView)findViewById(R.id.iconcurrent);
textCurrent = (TextView)findViewById(R.id.textcurrent);
textInfo = (TextView)findViewById(R.id.textinfo);
listForcast = (ListView)findViewById(R.id.listforcast);

buttonEnter.setOnClickListener(EnterOnClickListener);

}

Button.OnClickListener EnterOnClickListener
= new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String place = edittextPlace.getText().toString();

String weatherString = QueryGoogleWeather(place);
Document weatherDoc = convertStringToDocument(weatherString);

if(parseGoogleWeather(weatherDoc)){
//Display Result
String c = currentConditions.condition + "\n"
+ currentConditions.temp_f + "f\n"
+ currentConditions.temp_c + "c\n"
+ currentConditions.humidity + "\n"
+ currentConditions.wind_condition + "\n";

textCurrent.setText(c);
Bitmap bm = LoadIcon(currentConditions.icon);
iconCurrent.setImageBitmap(bm);

textInfo.setText("city: " + forecastInformation.city + "\n"
+ "postal code: " + forecastInformation.postal_code + "\n"
+ "forecast date: " + forecastInformation.forecast_date + "\n"
+ "current date time: " + forecastInformation.current_date_time + "\n"
+ "unit: " + forecastInformation.unit_system);

listForcast.setAdapter(new MyCustomAdapter(
AndroidGoogleWeatherActivity.this,
R.layout.row,
forecastConditionsList));
}


}

};

public class MyCustomAdapter extends ArrayAdapter<ForecastConditions> {

public MyCustomAdapter(Context context, int textViewResourceId,
List<ForecastConditions> objects) {
super(context, textViewResourceId, objects);
// TODO Auto-generated constructor stub
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.row, parent, false);
ImageView iconForecast = (ImageView)row.findViewById(R.id.iforecast);
TextView textForecast = (TextView)row.findViewById(R.id.tforecast);


textForecast.setText(
forecastConditionsList.get(position).day_of_week + "\n"
+ " - " + forecastConditionsList.get(position).condition + "\n"
+ forecastConditionsList.get(position).low + " ~ "
+ forecastConditionsList.get(position).high);

Bitmap bm = LoadIcon(forecastConditionsList.get(position).icon);
iconForecast.setImageBitmap(bm);

return row;
}

}

private Bitmap LoadIcon(String iconURL)
{
BitmapFactory.Options bmOptions;
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
String image_URL = "http://www.google.com" + iconURL;

Bitmap bitmap = null;
InputStream in = null;
try {
in = OpenHttpConnection(image_URL);
bitmap = BitmapFactory.decodeStream(in, null, bmOptions);
in.close();
} catch (IOException e1) {
}
return bitmap;
}

private InputStream OpenHttpConnection(String strURL) throws IOException{
InputStream inputStream = null;
URL url = new URL(strURL);
URLConnection conn = url.openConnection();

try{
HttpURLConnection httpConn = (HttpURLConnection)conn;
httpConn.setRequestMethod("GET");
httpConn.connect();

if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
inputStream = httpConn.getInputStream();
}
}catch (Exception ex){
}
return inputStream;
}

private boolean parseGoogleWeather(Document srcDoc){

boolean result = false;

forecastInformation = new ForecastInformation();
currentConditions = new CurrentConditions();

//-- Get forecast_information
NodeList forecast_information = srcDoc.getElementsByTagName("forecast_information");
if (forecast_information.getLength() > 0){

//Assume place found if "forecast_information" exist
result = true;

NodeList infoChilds = forecast_information.item(0).getChildNodes();

for(int i=0; i<infoChilds.getLength(); i++){
Node n = infoChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();
if (nName.equalsIgnoreCase("city")){
forecastInformation.city = nValue;
}else if((nName.equalsIgnoreCase("postal_code"))){
forecastInformation.postal_code = nValue;
}else if((nName.equalsIgnoreCase("forecast_date"))){
forecastInformation.forecast_date = nValue;
}else if((nName.equalsIgnoreCase("current_date_time"))){
forecastInformation.current_date_time = nValue;
}else if((nName.equalsIgnoreCase("unit_system"))){
forecastInformation.unit_system = nValue;
}
}
}

//-- Get current_conditions
NodeList current_conditions = srcDoc.getElementsByTagName("current_conditions");
if(current_conditions.getLength()>0){
NodeList currentChilds = current_conditions.item(0).getChildNodes();

for(int i=0; i<currentChilds.getLength(); i++){
Node n = currentChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();
if (nName.equalsIgnoreCase("condition")){
currentConditions.condition = nValue;
}else if((nName.equalsIgnoreCase("temp_f"))){
currentConditions.temp_f = nValue;
}else if((nName.equalsIgnoreCase("temp_c"))){
currentConditions.temp_c = nValue;
}else if((nName.equalsIgnoreCase("humidity"))){
currentConditions.humidity = nValue;
}else if((nName.equalsIgnoreCase("icon"))){
currentConditions.icon = nValue;
}else if((nName.equalsIgnoreCase("wind_condition"))){
currentConditions.wind_condition = nValue;
}
}
}

//-- Get forecast_conditions
NodeList forecast_conditions = srcDoc.getElementsByTagName("forecast_conditions");
if (forecast_conditions.getLength()>0){
int forecast_conditions_length = forecast_conditions.getLength();

forecastConditionsList = new ArrayList<ForecastConditions>();

for(int j=0; j<forecast_conditions_length; j++){

ForecastConditions tmpForecastConditions = new ForecastConditions();

NodeList forecasrChilds = forecast_conditions.item(j).getChildNodes();

for(int i=0; i<forecasrChilds.getLength(); i++){

Node n = forecasrChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();

if (nName.equalsIgnoreCase("condition")){
tmpForecastConditions.condition = nValue;
}else if((nName.equalsIgnoreCase("day_of_week"))){
tmpForecastConditions.day_of_week = nValue;
}else if((nName.equalsIgnoreCase("low"))){
tmpForecastConditions.low = nValue;
}else if((nName.equalsIgnoreCase("high"))){
tmpForecastConditions.high = nValue;
}else if((nName.equalsIgnoreCase("icon"))){
tmpForecastConditions.icon = nValue;
}
}
forecastConditionsList.add(tmpForecastConditions);
}
}

return result;
}

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

return dest;
}

private String QueryGoogleWeather(String p){

String uriPlace = Uri.encode(p);

String qResult = "";
String queryString = "http://www.google.com/ig/api?hl=en&weather=" + uriPlace;

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(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
}

return qResult;
}
}


main.xml layout
<?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" >

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/enter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="- Enter -"/>
<EditText
android:id="@+id/place"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<ImageView
android:id="@+id/iconcurrent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"/>
<TextView
android:id="@+id/textcurrent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:gravity="center"/>

</LinearLayout>
<TextView
android:id="@+id/textinfo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<ListView
android:id="@+id/listforcast"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ListView>
</LinearLayout>


row.xml, the row layout of the custom ListView.
<?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="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/iforecast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp" />
<TextView
android:id="@+id/tforecast"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>


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

Download the files.

3 comments:

SyedHashim said...

Can I use and modify this code for my App ? Thanks.

Erik said...

Hello SyedHashim,

OK. It's just a my personal exercise without any licence.

Anyway, it's appreciated if you can have a link to my blog here.

Thanks.

Unknown said...

Error : jar file as no source attachment...at

NodeList forecast_information = srcDoc.getElementsByTagName("forecast_information");