[Android] Parsing JSON with JSONObject

Android provides JSONObject and JsonReader for parsing JSON. JSONObject has been around since API level 1 (the first Android release), whereas JsonReader has been around only since API level 11 (Android 3). Here, we’ll look at using JSONObject using a demo.

The demo

The source code for this example is available from my GitHub repository. It simply creates a table containing observations from the JSON data included in the project (in res/raw/json.txt). The resulting table looks like this:

Contents of the JSON data

The sample JSON is a subset of weather observations for Perth Airport and was taken from the Bureau of Meteorology. The latest data is available on the observations page. Having said that, the demo will be actually using data in res/raw/json.txt instead of downloading the latest data (this will ensure that the demo still works if they decide to make changes). This is a sample of the contents:

{
	"observations": {
		"notice": [
			{
				"copyright": "Copyright Commonwealth of Australia 2012, Bureau of Meteorology. For more information see: http://www.bom.gov.au/other/copyright.shtml http://www.bom.gov.au/other/disclaimer.shtml",
				"copyright_url": "http://www.bom.gov.au/other/copyright.shtml",
				"disclaimer_url": "http://www.bom.gov.au/other/disclaimer.shtml",
				"feedback_url": "http://www.bom.gov.au/other/feedback"
			}
		],
		"header": [
			{
				"refresh_message": "Issued at  6:35 pm WST Tuesday 17 January 2012",
				"ID": "IDW60901",
				"main_ID": "IDW60900",
				"name": "Perth Airport",
				"state_time_zone": "WA",
				"time_zone": "WST",
				"product_name": "Capital City Observations",
				"state": "Western Australia"
			}
		],
		"data": [
			{
				"sort_order": 0,
				"wmo": 94610,
				"name": "Perth Airport",
				"history_product": "IDW60901",
				"local_date_time": "17/06:30pm",
				"local_date_time_full": "20120117183000",
				"aifstime_utc": "20120117103000",
				"air_temp": 27.6,
				"apparent_t": 23.0,
				"cloud": "-",
				"cloud_base_m": null,
				"cloud_oktas": null,
				"cloud_type": "-",
				"cloud_type_id": null,
				"delta_t": 9.4,
				"dewpt": 11.1,
				"gust_kmh": 33,
				"gust_kt": 18,
				"lat": -31.9,
				"lon": 116.0,
				"press": 1012.7,
				"press_msl": null,
				"press_qnh": 1012.7,
				"press_tend": "-",
				"rain_trace": "0.0",
				"rel_hum": 35,
				"sea_state": "-",
				"swell_dir_worded": "-",
				"swell_height": null,
				"swell_period": null,
				"vis_km": "10",
				"weather": "-",
				"wind_dir": "SSW",
				"wind_spd_kmh": 26,
				"wind_spd_kt": 14
			},
            ...
		]
	}
}

The demo will be using only a few of the fields from the observation data.

Using JSONObject

JSONObject will parse the data and provides accessors for extracting the data (see its documentation for a list of the accessors). The class provides a constructor that takes the entire JSON content as a string. The following snippet demonstrates how the demo creates the object:

private JSONObject getContent() throws IOException, JSONException {
    BufferedReader bufferedReader = null;
    try {
        InputStream inStream = getResources().openRawResource(R.raw.json);

        BufferedInputStream bufferedStream = new BufferedInputStream(
                inStream);
        InputStreamReader reader = new InputStreamReader(bufferedStream);
        bufferedReader = new BufferedReader(reader);
        StringBuilder builder = new StringBuilder();
        String line = bufferedReader.readLine();
        while (line != null) {
            builder.append(line);
            line = bufferedReader.readLine();
        }

       return new JSONObject(builder.toString());
    } finally {
        if (bufferedReader != null) {
            bufferedReader.close();
        }
    }
}

Note that we can create create a JSONObject directly because the data consists of a single JSON object. The observations are merely objects within it.

What if data consists of other types of objects?

It is possible that the data may contain something other than objects, such as an array. If you were to use try to create an instance with some other type, you would get an JSONException. A more flexible approach is to use JSONTokener instead:

JSONTokener tokener = new JSONTokener(builder.toString());
Object nextValue = tokener.nextValue();

Note that nextValue may return either a JSONObject, JSONArray, String, Boolean, Integer, Long, Double or NULL (see the documentation for details). An advantage of using JSONTokener is that it can also handle data containing multiple objects. For example, consider the following JSON data:

{
    "field": "value"
}
[
    "array 1",
    "array 2"
]
"text"

You can use JSONTokener to access each of the objects:

JSONTokener tokener = new JSONTokener(builder.toString());
while (tokener.more()) {
    Object value = tokener.nextValue();
    ...
}

If you created the JSONObject directly with the same data, it will provide only the first object in the data.

Looking for the data

The accessor methods in JSONObject makes it easy to extract the bits of data. Notice that the observation data consists of objects, in an array, in the “data” object. Getting to the array is only a matter of calling getJSONObject and then getJSONArray:

JSONArray dataArray = data.getJSONObject("observations").getJSONArray(
        "data");

JSONArray provides accessors to get to each object in the array (see the documentation for a full list). The following snippet, from the demo, runs through each of the objects, creates a row and adds it to the table:

for (int i = 0; i < dataArray.length(); i++) {
    final View row = createRow(dataArray.getJSONObject(i));
    table.post(new Runnable() {

        public void run() {
            table.addView(row);
        }
    });
}

The method createRow uses getString to get the field values and put it in a row:

private View createRow(JSONObject item) throws JSONException {
    View row = getLayoutInflater().inflate(R.layout.rows, null);
    ((TextView) row.findViewById(R.id.localTime)).setText(item
            .getString("local_date_time_full"));
    ((TextView) row.findViewById(R.id.apprentTemp)).setText(item
            .getString("apparent_t"));
    ((TextView) row.findViewById(R.id.windSpeed)).setText(item
            .getString("wind_spd_kmh"));
    return row;
}

That is all there is to using JSONObject! Although JSONObject makes it really easy to extract the bits of the data that we need, it also requires the entire object to be read into a String first. For a very large data set, this will cosume a lot of memory. The data used in the demo contained only three observations, but the source of the data actually contained many more! Another way of parsing JSON is to use JsonReader, which I’ll leave for another post (see Parsing JSON with JsonReader).

4 Responses to [Android] Parsing JSON with JSONObject

  1. Pingback: [Android] Parsing JSON with JsonReader « Kah – The Developer

  2. Hi there, i read your blog occasionally and i own a similar one and
    i was just curious if you get a lot of spam remarks? If so how do you reduce it,
    any plugin or anything you can recommend? I get so much lately it’s driving me mad so any support is very much appreciated.

    • kahgoh says:

      Hi,

      Sometimes I do get spam, but I don’t use any special plugins. Because this blog is hosted on wordpress.com, I use their default one (Akismet).

  3. asa says:

    Hi, really good post.

    one question of object is “data” in this sentence:
    JSONArray dataArray = data.getJSONObject(“observations”).getJSONArray(
    “data”);

    Because you are calling data.getJSON… where did you get the “data” varible?

    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: