In this Android tutorial, I will walk you through to access a web service end point, parse JSON response and display it in an Android list view. In the last Java tutorial we saw about creating a RESTful web service in Java that produces a JSON response. We will use that service to produce a sample JSON response and consume it via an example Android application.
Earlier I wrote an Android tutorial to read Twitter feeds, in that tutorial I accessed the Twitter API and consumed the JSON response. This tutorial is similar to that and has some improvements in code. The RESTful web service that produces the JSON response and the Android app that is going to consume the JSON response are in the same system.
Following Java class is a generic utility to access a network URI and read its response. This is a simple task and we need not go for a third-party API. We can have this as a based code and extend over it.
package com.javapapers.android.util; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Log; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; public class AndroidNetworkUtility { private static final String TAG = "AndroidNetworkUtility"; public boolean isConnected(Context ctx) { boolean flag = false; ConnectivityManager connectivityManager = (ConnectivityManager) ctx.getSystemService(ctx.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected()) { flag = true; } return flag; } public String getHttpResponse(HttpRequestBase request) { String result = null; InputStream inputStream = null; try { Log.d(TAG, "about to instantiate DefaultHttpClient"); DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams()); Log.d(TAG, "got httpClient" + request.getURI().toString()); HttpResponse httpResponse = httpClient.execute(request); Log.d(TAG, "got httpResponse"); int statusCode = httpResponse.getStatusLine().getStatusCode(); Log.d(TAG, "Status Code: " + statusCode); String reason = httpResponse.getStatusLine().getReasonPhrase(); Log.d(TAG, "Reason: " + reason); StringBuilder sb = new StringBuilder(); if (statusCode == 200) { HttpEntity entity = httpResponse.getEntity(); inputStream = entity.getContent(); BufferedReader bReader = new BufferedReader( new InputStreamReader(inputStream, "UTF-8"), 8); String line = null; while ((line = bReader.readLine()) != null) { sb.append(line); } } else { sb.append(reason); } result = sb.toString(); Log.d(TAG, result); } catch (UnsupportedEncodingException ex) { Log.e(TAG, ex.toString()); ex.printStackTrace(); } catch (ClientProtocolException ex1) { Log.e(TAG, ex1.toString()); ex1.printStackTrace(); } catch (IOException ex2) { Log.e(TAG, ex2.toString()); ex2.printStackTrace(); } finally { Log.d(TAG, "finally ............."); try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } Log.d(TAG, result); return result; } }
Following service class uses the above given util class to connect the web service URI and consume JSON response. This again can be considered a generic class and can be ported easily to any other domain specific uses. Following are the two areas to note in this,
Add the following dependency to app Gradle dependencies file. Hope you are using Android Studio and if not, I highly recommend to migrate.
dependencies { compile 'com.google.code.gson:gson:2.3.1' }
In the example Android application, I am accessing a RESTful web service that is deloplyed in my local system. The IP address given in the code is my systems local IP address. You can use any web service that produces a JSON response for this example. All you need to do is to give the URI and create a domain object that maps the response.
package com.javapapers.android.jsonparsing; import android.util.Log; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.javapapers.android.util.AndroidNetworkUtility; import org.apache.http.client.methods.HttpGet; import java.util.ArrayList; public class ProductService { private static final String TAG = "ProductService"; private static final String PRODUCT_WEB_SERVICE_URL = "http://192.168.1.11:8080/JSON_RESTful_Service/rest/products"; public ArrayList<Product> getProducts() { Log.i(TAG, "getProducts ......"); ArrayList<Product> productList = null; HttpGet httpGet = new HttpGet(PRODUCT_WEB_SERVICE_URL); //setting header to request for a JSON response httpGet.setHeader("Accept", "application/json"); AndroidNetworkUtility httpUtil = new AndroidNetworkUtility(); String productJSONStr = httpUtil.getHttpResponse(httpGet); Log.d(TAG, "Response: " + productJSONStr); productList = convertJson(productJSONStr); return productList; } private ArrayList<Product> convertJson(String productJSONStr) { ArrayList<Product> productList = null; if (productJSONStr != null && productJSONStr.length() > 0) { try { Gson gson = new Gson(); productList = gson.fromJson(productJSONStr, new TypeToken<ArrayList<Product>>() { }.getType()); } catch (IllegalStateException e) { e.printStackTrace(); } } return productList; } }
With this key part of this tutorial is done. Accessing the web service end point URI and parsing the JSON response is done. Now the result values are available in an ArrayList instance and we need to display it in a an Android list view. I have earlier written many tutorials for Android list view. Refer this Android ListView custom layout tutorial or continue reading here.
package com.javapapers.android.jsonparsing; import android.app.Activity; import android.os.Bundle; import android.util.Log; import com.javapapers.android.util.AndroidNetworkUtility; public class MainActivity extends Activity { final static String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); AndroidNetworkUtility androidNetworkUtility = new AndroidNetworkUtility(); if (androidNetworkUtility.isConnected(this)) { Log.i(TAG, "Connected."); new ProductAsyncTask().execute(this); } else { Log.v(TAG, "Network not Available!"); } } }
<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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:background="@android:color/holo_purple"> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/prodsLV" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="0dp" android:layout_marginTop="0dp" android:dividerHeight="1dp" android:divider="@android:color/black" /> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginBottom="0dp" android:layout_marginTop="0dp" android:focusableInTouchMode="true" android:paddingTop="10dp" android:paddingBottom="5dp"> <TextView android:id="@+id/id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:paddingRight="10dp" android:paddingTop="10dp" android:paddingLeft="10dp" android:scaleType="centerCrop" android:textColor="@android:color/black" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/id" android:layout_centerVertical="true" android:paddingTop="10dp" android:text="Cherry" android:textColor="#ffffffff" /> <TextView android:id="@+id/category" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:paddingTop="15dp" android:paddingRight="15dp" android:textColor="#ffffffff" /> </RelativeLayout>
package com.javapapers.android.jsonparsing; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class ProductArrayAdapter extends ArrayAdapter<Product> { private static final String TAG = "ProductArrayAdapter"; private List<Product> productList = new ArrayList<Product>(); static class ProductViewHolder { TextView id; TextView name; TextView category; } public ProductArrayAdapter(Context context, int textViewResourceId) { super(context, textViewResourceId); } @Override public void add(Product object) { productList.add(object); super.add(object); } @Override public int getCount() { return this.productList.size(); } @Override public Product getItem(int index) { return this.productList.get(index); } @Override public View getView(int position, View convertView, ViewGroup parent) { View row = convertView; ProductViewHolder viewHolder; if (row == null) { LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); row = inflater.inflate(R.layout.listview_row_layout, parent, false); viewHolder = new ProductViewHolder(); viewHolder.id = (TextView) row.findViewById(R.id.id); viewHolder.name = (TextView) row.findViewById(R.id.name); viewHolder.category = (TextView) row.findViewById(R.id.category); row.setTag(viewHolder); } else { viewHolder = (ProductViewHolder) row.getTag(); } Product product = getItem(position); viewHolder.id.setText(product.getId()); viewHolder.name.setText(product.getName()); viewHolder.category.setText(product.getCategory()); return row; } public Bitmap decodeToBitmap(byte[] decodedByte) { return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length); } }
Network calls should not be made from the primary UI thread activity. I have created an AsyncTask and will make the network call to access the web service URI from it.
package com.javapapers.android.jsonparsing; import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.util.Log; import android.widget.ListView; import java.util.ArrayList; public class ProductAsyncTask extends AsyncTask<Object, Void, ArrayList<Product>> { Activity callerActivity; private Context mContext; private ProductArrayAdapter productArrayAdapter; private ListView listView; private static final String TAG = "ProductAsyncTask"; @Override protected ArrayList<Product> doInBackground(Object... params) { Log.i(TAG, "doing in background :) "); ArrayList<Product> productList = null; mContext = (Context) params[0]; callerActivity = (Activity) params[0]; ProductService productService = new ProductService(); Log.i(TAG, "ProductService instantiated ....................."); productList = productService.getProducts(); Log.d(TAG, "COUNT: " + productList.size()); return productList; } @Override protected void onPostExecute(ArrayList<Product> productList) { listView = (ListView) callerActivity.findViewById(R.id.prodsLV); productArrayAdapter = new ProductArrayAdapter(mContext, R.layout.listview_row_layout); for (Product product : productList) { productArrayAdapter.add(product); } listView.setAdapter(productArrayAdapter); } }
Following is the domain class:
package com.javapapers.android.jsonparsing; public class Product { private String id; private String name; private String category; public Product() { } public Product(String id, String name, String category) { super(); this.id = id; this.name = name; this.category = category; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } }
Download the Android application project AndroidJSONParsing
Comments are closed for "Android JSON Parsing Tutorial".
Finally we arrived at JSON by the way. But you know why i inspired write comment?
.
I Got My Java Cup Again on the top of the page.
Cheers.
@Firoz,
Thanks. I keep changing the design based on user feedback.
I changed the previous notepad design in order to improve the page load speed. But, got some good amount of comments asking me to go back to the notepad with coffee cup design.
Now what I have taken the best of sleek design and merged it with the old notepad+cup design. Hope you guys like it.
Thanks for wrote down the tutorial and shared the project file with newbies like me. May I suggest you to host each project using public git repo such github. By this way, you bandwidth will be reduce and if anything happen with hosting, thus file still available.
@krip,
That’s a good idea. Sure I will look at hosting the code samples in github kind of public repos.