VOOZH about

URL: https://www.javacodegeeks.com/2013/06/android-build-real-weather-app-json-http-and-openweathermap.html

โ‡ฑ Android: Build real weather app: JSON, HTTP and Openweathermap


In this post I want to describe how to create a weather app that gives current weather information. This app will use JSON, HTTP connection and AsyncTask to get this information.. As weather provider I will use OpenWeatherMap a free weather service that provides some interesting API really easy to use.I will guide you through the steps necessary to build up a working app. For more information about API, you can visit the OpenWeatherMap web site. I will show to you the final result so you can have an idea about what we will do in this post.

๐Ÿ‘ Image

Current weather info โ€“ HTTP Request and JSON Response

OpenWeatherMap offers several API to use to get weather information. We want to use the one that gives us the current weather info. The URL to call to get this info is:

http://api.openweathermap.org/data/2.5/weather?q=city,country

Letโ€™s suppose we want to know the weather in Rome, IT. Using our browser we can have:

๐Ÿ‘ weather_api_search

As we can see we have JSON response. Formatting the response we have

{
 "coord":{"lon":12.4958,"lat":41.903},
 "sys":{"country":"Italy","sunrise":1369107818,"sunset":1369160979},
 "weather":[{
 "id":802,"main":"Clouds","description":"scattered clouds",
 "icon":"03d"}],
 "base":"global stations",
 "main":{
 "temp":290.38,
 "humidity":68,
 "pressure":1015,
 "temp_min":287.04,
 "temp_max":293.71},
 "wind":{ 
 "speed":1.75,
 "deg":290.002},
 "clouds":{"all":32},
 "dt":1369122932,
 "id":3169070,
 "name":"Rome",
 "cod":200
}

So the first thing we need to do is creating our data model so that we can parse the response and convert it into Java classes. Analyzing the response we have different โ€œmainโ€ tags that we can use as class in Java:

  • coord (object)
  • sys (object)
  • weather (array)
  • main (object)
  • wind (object)
  • name: (String)

The response is quite simple and we can convert it manually. The UML class diagram for the model is shown below:

๐Ÿ‘ Image

JSON Weather Parser

Once we have created our model we have to parse it. We can create a specific class that handles this task. First we have to create the โ€œrootโ€ object that receive as input the entire string containing all the JSON response:

// We create out JSONObject from the data
JSONObject jObj = new JSONObject(data);

Then we start parsing each piece of the response:

// We start extracting the info
Location loc = new Location();

JSONObject coordObj = getObject("coord", jObj);
loc.setLatitude(getFloat("lat", coordObj));
loc.setLongitude(getFloat("lon", coordObj));

JSONObject sysObj = getObject("sys", jObj);
loc.setCountry(getString("country", sysObj));
loc.setSunrise(getInt("sunrise", sysObj));
loc.setSunset(getInt("sunset", sysObj));
loc.setCity(getString("name", jObj));
weather.location = loc;

In the line 4,8 we create two โ€œsubโ€ object (coordObj and sysObj) having as parent the jObj as it clear from the JSON response. As we can see we use some helper methods to get String,int and float values:

private static JSONObject getObject(String tagName, JSONObject jObj) throws JSONException {
 JSONObject subObj = jObj.getJSONObject(tagName);
 return subObj;
}

private static String getString(String tagName, JSONObject jObj) throws JSONException {
 return jObj.getString(tagName);
}

private static float getFloat(String tagName, JSONObject jObj) throws JSONException {
 return (float) jObj.getDouble(tagName);
}

private static int getInt(String tagName, JSONObject jObj) throws JSONException {
 return jObj.getInt(tagName);
}

And then we finally parse the weather information. We have to remember that weather tag is an array so we have to handle it differently

// We get weather info (This is an array)
JSONArray jArr = jObj.getJSONArray("weather");

// We use only the first value
JSONObject JSONWeather = jArr.getJSONObject(0);
weather.currentCondition.setWeatherId(getInt("id", JSONWeather));
weather.currentCondition.setDescr(getString("description", JSONWeather));
weather.currentCondition.setCondition(getString("main", JSONWeather));
weather.currentCondition.setIcon(getString("icon", JSONWeather));

JSONObject mainObj = getObject("main", jObj);
weather.currentCondition.setHumidity(getInt("humidity", mainObj));
weather.currentCondition.setPressure(getInt("pressure", mainObj));
weather.temperature.setMaxTemp(getFloat("temp_max", mainObj));
weather.temperature.setMinTemp(getFloat("temp_min", mainObj));
weather.temperature.setTemp(getFloat("temp", mainObj));

// Wind
JSONObject wObj = getObject("wind", jObj);
weather.wind.setSpeed(getFloat("speed", wObj));
weather.wind.setDeg(getFloat("deg", wObj));

// Clouds
JSONObject cObj = getObject("clouds", jObj);
weather.clouds.setPerc(getInt("all", cObj));

At the end we have our Weather class filled with the data retrieved.

HTTP Request and Response

Now we have to exchange information with the remote server using HTTP protocol. We have to send information and then read the response. We covered this topic in the previous post( Android HTTP Client: GET, POST, Download, Upload, Multipart Request) so we wonโ€™t describe it again, we simply show the code:

public class WeatherHttpClient {

 private static String BASE_URL = "http://api.openweathermap.org/data/2.5/weather?q=";
 private static String IMG_URL = "http://openweathermap.org/img/w/";

 public String getWeatherData(String location) {
 HttpURLConnection con = null ;
 InputStream is = null;

 try {
 con = (HttpURLConnection) ( new URL(BASE_URL + location)).openConnection();
 con.setRequestMethod("GET");
 con.setDoInput(true);
 con.setDoOutput(true);
 con.connect();

 // Let's read the response
 StringBuffer buffer = new StringBuffer();
 is = con.getInputStream();
 BufferedReader br = new BufferedReader(new InputStreamReader(is));
 String line = null;
 while ( (line = br.readLine()) != null )
 buffer.append(line + "\r\n");

 is.close();
 con.disconnect();
 return buffer.toString();
 }
 catch(Throwable t) {
 t.printStackTrace();
 }
 finally {
 try { is.close(); } catch(Throwable t) {}
 try { con.disconnect(); } catch(Throwable t) {}
 }

 return null;

 }

 public byte[] getImage(String code) {
 HttpURLConnection con = null ;
 InputStream is = null;
 try {
 con = (HttpURLConnection) ( new URL(IMG_URL + code)).openConnection();
 con.setRequestMethod("GET");
 con.setDoInput(true);
 con.setDoOutput(true);
 con.connect();

 // Let's read the response
 is = con.getInputStream();
 byte[] buffer = new byte[1024];
 ByteArrayOutputStream baos = new ByteArrayOutputStream();

 while ( is.read(buffer) != -1)
 baos.write(buffer);

 return baos.toByteArray();
 }
 catch(Throwable t) {
 t.printStackTrace();
 }
 finally {
 try { is.close(); } catch(Throwable t) {}
 try { con.disconnect(); } catch(Throwable t) {}
 }

 return null;

 }
}

Weather App

Finally, it is the time for our Activity. The layout is very simple and of course it is just a skeleton you need to improve it if you want to have a production app.

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
 android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context=".MainActivity" >

 <TextView
 android:id="@+id/cityText"
 style="?android:attr/textAppearanceMedium"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerHorizontal="true" />

 <ImageView
 android:id="@+id/condIcon"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentLeft="true"
 android:layout_below="@id/cityText" />

 <TextView
 android:id="@+id/condDescr"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_below="@id/condIcon"
 android:layout_alignLeft="@id/condIcon" 
 />

 <TextView
 android:id="@+id/temp"
 style="@style/tempStyle"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="12dp"
 android:layout_alignBaseline="@id/condDescr"
 android:layout_toRightOf="@id/condDescr"/>

 <TextView
 android:id="@+id/pressLab"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentLeft="true"
 android:layout_below="@id/condDescr"
 android:text="Pressure"
 android:layout_marginTop="15dp" />

 <TextView
 android:id="@+id/press"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignBaseline="@id/pressLab"
 android:layout_toRightOf="@id/pressLab" 
 style="@style/valData"/>

 <TextView
 android:id="@+id/humLab"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentLeft="true"
 android:layout_below="@id/pressLab"
 android:text="Humidity" />

 <TextView
 android:id="@+id/hum"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignBaseline="@id/humLab"
 android:layout_toRightOf="@id/humLab" 
 android:layout_marginLeft="4dp"
 style="@style/valData"/>

 <TextView
 android:id="@+id/windLab"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentLeft="true"
 android:layout_below="@id/humLab"
 android:text="Wind" />

 <TextView
 android:id="@+id/windSpeed"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignBaseline="@id/windLab"
 android:layout_toRightOf="@id/windLab"
 android:layout_marginLeft="4dp"
 style="@style/valData" />

 <TextView
 android:id="@+id/windDeg"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignBaseline="@id/windLab"
 android:layout_toRightOf="@id/windSpeed"
 android:layout_marginLeft="4dp" 
 style="@style/valData"/>

</RelativeLayout>

In onCreate method we simply get the reference to the Views inside the layout so that we can populate them later after the request is completed.

@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 String city = "Rome,IT";

 cityText = (TextView) findViewById(R.id.cityText);
 condDescr = (TextView) findViewById(R.id.condDescr);
 temp = (TextView) findViewById(R.id.temp);
 hum = (TextView) findViewById(R.id.hum);
 press = (TextView) findViewById(R.id.press);
 windSpeed = (TextView) findViewById(R.id.windSpeed);
 windDeg = (TextView) findViewById(R.id.windDeg);
 imgView = (ImageView) findViewById(R.id.condIcon);

 JSONWeatherTask task = new JSONWeatherTask();
 task.execute(new String[]{city});
}

and we start an AsyncTask, because as we already know network operations are time consuming so we can run them in the main thread otherwise we could have an ANR problem. The JSONWeatherTask is very simply

protected Weather doInBackground(String... params) {
 Weather weather = new Weather();
 String data = ( (new WeatherHttpClient()).getWeatherData(params[0]));

 try {
 weather = JSONWeatherParser.getWeather(data);

 // Let's retrieve the icon
 weather.iconData = ( (new WeatherHttpClient()).getImage(weather.currentCondition.getIcon()));

 } catch (JSONException e) { 
 e.printStackTrace();
 }
 return weather;

 }

At line 3 we make the HTTP request and then we parse it at line 6. At line 9 we retrieve the icon that shows the weather condition.

Running the code we have:

๐Ÿ‘ Image
๐Ÿ‘ Image

The source code available @github.
 

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

๐Ÿ‘ Photo of Francesco Azzola
Francesco Azzola
June 12th, 2013Last Updated: June 12th, 2013
17 756 5 minutes read

Francesco Azzola

He's a senior software engineer with more than 15 yrs old experience in JEE architecture. He's SCEA certified (Sun Certified Enterprise Architect), SCWCD, SCJP. He is an android enthusiast and he has worked for long time in the mobile development field.
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

17 Comments
Oldest
Newest Most Voted
Raul Pop
12 years ago

Really great tutorial :)
Thank you!

Also, I have a question: If I want to use my own icons for weather, can I do that?

0
Reply
12 years ago
Reply to  Raul Pop

You can do it remapping weather icon code. If you look at the code thereโ€™s a piece of it downloading an icon that is the weather icon. You can map this icon code to your icon.

0
Reply
nikhil
12 years ago

ammโ€ฆi m a beginner at this oneโ€ฆcud u pls upload the whole codeโ€ฆi couldnt get some of the parts aboveโ€ฆ

0
Reply
12 years ago
Reply to  nikhil

Look at the original post here: http://www.survivingwithandroid.com/2013/05/build-weather-app-json-http-android.html
You can find the link to download the code at github.

0
Reply
bobby
12 years ago

hi, m also a beginner my location object Location loc = new Location(); gives me an error i imported location classes, What am i missing.

0
Reply
12 years ago

Can you post the stacktrace so that i can have an idea on your error. Thank you.

0
Reply
Madhu
12 years ago

Thanks a Lot nice tutorials helped me a lot,.. if you have any donations i will donate 10% of my salary thanks a lot i am really impressed

0
Reply
12 years ago

Im trying to have the user input the location, so I did this:

1. Added a button with id button1 in activity_main.xml
2. Changed cityText to EditText in activity_main.xml
3. Commented out the setting of String city in Main
4. Set location to be cast as EditText in order to get the cityText view
5. Added a public void open (View view) method to:
โ€“ String city = location.getText().toString();
โ€“ JSONWeatherTask task = new JSONWeatherTask();
โ€“ task.execute(new String[]{city});

but the app just crashes. Actually i put a:

System.out.printf(โ€œbuttonClickedโ€);

in that method but it doesnโ€™t seem to log. Can you help?

0
Reply
Ahmed
12 years ago

Hi, Im beginner in android and I have to make an weather app. My problem here is the data model, I didnโ€™t get how to do the data model.
Iโ€™ll be grateful โ€ฆ
Thank you. l

0
Reply
Tanvi
12 years ago

Thanks a ton! Great help!

0
Reply
lai
12 years ago

i cant get the icon data?How can solve problem.
public byte[] getImage(String code) {
HttpURLConnection con = null ;
InputStream is = null;
try {
con = (HttpURLConnection) ( new URL(IMG_URL + code)).openConnection();
con.setRequestMethod(โ€œGETโ€);
con.setDoInput(true);
con.setDoOutput(true);
con.connect();

// Letโ€™s read the response
is = con.getInputStream();
byte[] buffer = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();

while ( is.read(buffer) != -1)
baos.write(buffer);

return baos.toByteArray();
}
catch(Throwable t) {
t.printStackTrace();
}
finally {
try { is.close(); } catch(Throwable t) {}
try { con.disconnect(); } catch(Throwable t) {}
}

return null;

}

0
Reply
Abdul Basit
11 years ago

How to Convert sunset and sunrise time into minute???

0
Reply
Cherry
11 years ago
Reply to  Abdul Basit

public static String TimeStamp2Date(String timestampString) {
Long timestamp = Long.parseLong(timestampString) * 1000;
String date = new java.text.SimpleDateFormat(โ€œyyyy-MM-dd HH:mm:ssโ€)
.format(new java.util.Date(timestamp));
return date;
}

1
Reply
Nasir
11 years ago

How can I convert โ€œsunriseโ€: 1428450217, โ€œsunsetโ€: 1428495411 to actual time.

0
Reply
Nasir
11 years ago
Reply to  Nasir

Sorry I got this from last comment

0
Reply
Nasir
11 years ago

Ho can I convert โ€œhumidityโ€: 100 to percent?

0
Reply
Serius Black
10 years ago

I was always having confusion about parsing the json string. after reading your tutorial I really understand the basics about converting json formate.

Thanks Alot

0
Reply
Back to top button
Close
wpDiscuz