http://sundaydevblog.com/blog/post/android-json-parsing-from-rest-service-example

What is a JSON?

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is:

  • easy for humans to read and write
  • easy for machines to parse and generate
  • based on a subset of the JavaScript Programming Language
  • a text format that is completely language independent

JSON is often used to exchange data between a user (browser or any other program) and a server. The data can only be a text and values must be one of the following data types:

  • a string
  • a number
  • an object (JSON object)
  • an array
  • a boolean
  • null

This allows to construct a data hierarchy, like so:

1505579958.png

What is parsing?
Parsing is the act of reading text (in this case it's the JSON) and converting it into a more useful information format, like a data types: string, integer or array.



☛ The JSON Parsing Demo code is available to download from the GitHub: 


1. Introduction 
Let's build now an Android application that will retrieve the JSON, convert it to a String object, then parse it to variables and populate it to the user.

To do so, we will use a free REST API service to work on a fake data. In this example, I will use the JSONPlaceholder.typicode.com which allows us to download a fake users list.
The URL is ‘https://jsonplaceholder.typicode.com/users/USER_ID' where USER_ID is a user number which can be between 1 and 10. To display a whole user list just leave USER_ID blank.

Sample JSON query result from JSONPlaceholder REST API service (https://jsonplaceholder.typicode.com/users/1)

{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    "city": "Gwenborough",
    "zipcode": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "company": {
    "name": "Romaguera-Crona",
    "catchPhrase": "Multi-layered client-server neural-net",
    "bs": "harness real-time e-markets"
  }
}

2. Create New Project
Create a new project and give it a name ‘JSON Parsing Demo'. Select ‘Empty Activity'.

3. Add INTERNET permission
As we will be fetching the JSON by making HTTP calls, we need to add following permission in AndroidManifest.xml file (located in ‘manifests' folder).

<uses-permission android:name="android.permission.INTERNET" />

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sundaydevblog.jsonparsingdemo">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

4. Create Data Model class
In this example, I would like to use:
  • user name
  • email address
  • phone number
  • website address
  • and home address (street, suite, postcode and city name)
As we see in JSON all these values are Strings. Let's create a two data classes. One for address and the second for the user which will inheritance from address class.

UserModel.java
public class UserModel extends AddressModel {
    private final String name;
    private final String email;
    private final String phone;
    private final String website;

    public UserModel(String name, String email, String phone, String website, String street, String suite, String city, String postcode) {
        super(street, suite, city, postcode);
        this.name = name;
        this.email = email;
        this.phone = phone;
        this.website = website;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public String getPhone() {
        return phone;
    }

    public String getWebsite() {
        return website;
    }
}

AddressModel.java
public class AddressModel {

    private final String street;
    private final String suite;
    private final String city;
    private final String postcode;

    public AddressModel(String street, String suite, String city, String postcode) {
        this.street = street;
        this.suite = suite;
        this.city = city;
        this.postcode = postcode;
    }

    public String getStreet() {
        return street;
    }

    public String getSuite() {
        return suite;
    }

    public String getCity() {
        return city;
    }

    public String getPostcode() {
        return postcode;
    }
}

5. Create layout
To create a layout, I will use a TextView wrapped into RelativeLayout container to keep it very simple. Open the layout file of main activity ‘activity_main.xml' and add following code.

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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:padding="16dp"
    tools:context="com.sundaydevblog.jsonparsingdemo.MainActivity">

    <TextView
        android:id="@+id/title_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/name_title"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/title_address"
        android:textAppearance="?android:attr/textAppearanceMedium"
        tools:text="User Name" />

    <TextView
        android:id="@+id/title_email"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title_name"
        android:text="@string/email_title"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/email"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/name"
        android:layout_toEndOf="@+id/title_address"
        android:textAppearance="?android:attr/textAppearanceMedium"
        tools:text="user@email.com" />

    <TextView
        android:id="@+id/title_phone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title_email"
        android:text="@string/phone_title"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/phone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/email"
        android:layout_toEndOf="@+id/title_address"
        android:textAppearance="?android:attr/textAppearanceMedium"
        tools:text="0123456789" />

    <TextView
        android:id="@+id/title_website"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title_phone"
        android:text="@string/website_title"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/website"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/phone"
        android:layout_toEndOf="@+id/title_address"
        android:textAppearance="?android:attr/textAppearanceMedium"
        tools:text="website.com" />

    <TextView
        android:id="@+id/title_address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title_website"
        android:layout_marginEnd="8dp"
        android:layout_marginTop="8dp"
        android:text="@string/address_title"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/website"
        android:layout_marginTop="8dp"
        android:layout_toEndOf="@+id/title_address"
        android:textAppearance="?android:attr/textAppearanceMedium"
        tools:text="Street 123 \nPostcode \nCity" />

</RelativeLayout>

6. Create HttpHandler
Now we need to create a HttpHandler.java class with following methods:
  • createUrl() - to create new URL object from the given string URL
  • makeHttpRequest() - get raw JSON from the URL object
  • readFromStream() - convert JSON into a String
  • extractFeatureFromJson() - to parse JSON String into the user object

HttpHandler.java
import android.text.TextUtils;
import android.util.Log;

import com.sundaydevblog.jsonparsingdemo.Models.UserModel;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;

public class HttpHandler {

    /**
     * Tag for the log messages
     */
    private static final String TAG = HttpHandler.class.getSimpleName();

    /**
     * Returns new URL object from the given string URL.
     */
    public URL createUrl(String stringUrl) {
        URL url;
        try {
            url = new URL(stringUrl);
        } catch (MalformedURLException exception) {
            Log.e(TAG, "Error with creating URL", exception);
            return null;
        }
        return url;
    }

    /**
     * Make an HTTP request to the given URL and return a String as the response.
     */
    public String makeHttpRequest(URL url) throws IOException {
        String jsonResponse = "";

        // If the URL is null, then return early.
        if (url == null) {
            return jsonResponse;
        }

        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        try {
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.setReadTimeout(10000 /* milliseconds */);
            urlConnection.setConnectTimeout(15000 /* milliseconds */);
            urlConnection.connect();

            // If the request was successful (response code 200),
            // then read the input stream and parse the response.
            if (urlConnection.getResponseCode() == 200) {
                inputStream = urlConnection.getInputStream();
                jsonResponse = readFromStream(inputStream);
            } else {
                Log.e(TAG, "Error response code: " + urlConnection.getResponseCode());
            }
        } catch (IOException e) {
            Log.e(TAG, "Problem retrieving the user JSON results.", e);
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return jsonResponse;
    }

    /**
     * Convert the {@link InputStream} into a String which contains the
     * whole JSON response from the server.
     */
    private String readFromStream(InputStream inputStream) throws IOException {
        StringBuilder output = new StringBuilder();
        if (inputStream != null) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
            BufferedReader reader = new BufferedReader(inputStreamReader);
            String line = reader.readLine();
            while (line != null) {
                output.append(line);
                line = reader.readLine();
            }
        }
        return output.toString();
    }

    /**
     * Return an {@link UserModel} object by parsing out information
     * about the user from the input userJSON string.
     */
    UserModel extractFeatureFromJson(String userJSON) {
        // If the JSON string is empty or null, then return early.
        if (TextUtils.isEmpty(userJSON)) {
            return null;
        }

        try {
            // Extract out the user name, email, phone and website values
            JSONObject baseJsonResponse = new JSONObject(userJSON);
            String name = baseJsonResponse.getString("name");
            String email = baseJsonResponse.getString("email");
            String phone = baseJsonResponse.getString("phone");
            String website = baseJsonResponse.getString("website");

            // Extract out the user address values
            JSONObject address = baseJsonResponse.getJSONObject("address");
            String street = address.getString("street");
            String suite = address.getString("suite");
            String city = address.getString("city");
            String postcode = address.getString("zipcode");

            // Create a new {@link UserModel} object
            return new UserModel(name, email, phone, website, street, suite, city, postcode);

        } catch (JSONException e) {
            Log.e(TAG, "Problem parsing the user JSON results", e);
        }
        return null;
    }

}

7. Async, threading and MainActivity class
As we want to fetch the JSON using HTTP request (task), we need to add UserAsyncTask class into MainActvity.java to make the request on the background thread. We need this to not blocking the main thread which is responsible for handling the user interface in terms of event handling and interaction with views in the user interface.
In the MainActivity class we need to add following methods:
  • doInBackground() – invoked on the background thread to get JSON from URL
  • onPostExecute() – invoked on the UI thread after the background task finishes
  • updateUi() – update the screen to display information from user data model
I'm aware that threading is quite vast and complex topic in Android Development and it can be challenging even for experienced developers. That's why I will not elaborate any further in this post. Asynchronous threading is beyond the scope of this tutorial.

MainActivity.java
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.sundaydevblog.jsonparsingdemo.Models.UserModel;

import java.io.IOException;
import java.net.URL;
import java.util.Random;

/**
 * Displays information about a user.
 */

public class MainActivity extends AppCompatActivity {

    /**
     * Tag for the log messages
     */
    private static final String TAG = MainActivity.class.getSimpleName();

    /**
     * URL to get JSON user data
     */
    private static final String BASE_URL = "https://jsonplaceholder.typicode.com/users/";

    /**
     * Instantiate Random class object to generate random user number to use with a BASE_URL
     */
    private static Random random = new Random();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        UserAsyncTask task = new UserAsyncTask();
        task.execute();
    }

    private class UserAsyncTask extends AsyncTask<URL, Void, UserModel> {
        HttpHandler handler = new HttpHandler();

        @Override
        protected UserModel doInBackground(URL... urls) {
            // Generate a random number in the range 1..10
            String userRandomNumber = String.valueOf(random.nextInt(10 - 1 + 1) + 1);
            URL url = handler.createUrl(BASE_URL + userRandomNumber);

            // Perform HTTP request to the URL and receive a JSON response back
            String jsonResponse = "";
            try {
                jsonResponse = handler.makeHttpRequest(url);
            } catch (IOException e) {
                Log.e(TAG, "Problem making the HTTP request.", e);
            }

            // Extract relevant fields from the JSON response and return the {@link UserModel} object as the result fo the {@link UserAsyncTask}
            return handler.extractFeatureFromJson(jsonResponse);
        }

        /**
         * Update the screen with the given user (which was the result of the
         * {@link UserAsyncTask}).
         */
        @Override
        protected void onPostExecute(UserModel userModel) {
            if (userModel == null) {
                Toast.makeText(MainActivity.this, "Couldn't get JSON from server. Check LogCat for possible errors!", Toast.LENGTH_LONG).show();
                return;
            }

            updateUi(userModel);
        }

        /**
         * Update the screen to display information from the given {@link UserModel}.
         */
        private void updateUi(UserModel user) {

            TextView name = (TextView) findViewById(R.id.name);
            name.setText(user.getName());

            TextView email = (TextView) findViewById(R.id.email);
            email.setText(user.getEmail());

            TextView phone = (TextView) findViewById(R.id.phone);
            phone.setText(user.getPhone());

            TextView website = (TextView) findViewById(R.id.website);
            website.setText(user.getWebsite());

            TextView address = (TextView) findViewById(R.id.address);
            address.setText(getString(R.string.address_text, user.getStreet(), user.getSuite(), user.getPostcode(), user.getCity()));
        }
    }
}

◉ Results:

1505581978.png

☛ The JSON Parsing Demo code is available to download from the GitHub: