Android Custom Expandable ListView Using JSON Over Http

By | February 17, 2015

In the previous series of tutorial we have seen how to create Android simple expandable listview and custom expandable listview there we are using data initialized in local android resource , here in this tutorial we will see how to create custom expandable listview over json by making http request using volley library.

As the ICC Cricket world cup going a perfect example that came in my mind for this tutorial is grouping countries into there specific group .

Below is the Screen Shot of final output.


Project Detail

Project Name ExpandableListDemo
Package com.pavan.expandablelistdemo
Minimum SDK API 8
Target SDK API 17
Theme Holo Light with Dark Action Bar

JSON Structure

Here In this tutorial we are going to parse the json object from remote URL which is located at http://api.tutorialsbuzz.com/cricketworldcup2015/cricket.json

First we need to build a project with volley library which i have discussed in my previous tutorial
how Build project with Volley .

Manifest

 Add the internet permission inside the manifest file

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

XML Layout

Create XML Layouts inside the res/layout directory of your project
  1. activity_main.xml
  2. group_item.xml
  3. child_item.xml
Create activity_main.xml file and Add Expandable ListView element.
file : 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”
    tools:context=”.MainActivity” >

    <ExpandableListView
        android:id=”@+id/exp_list”
        android:layout_width=”match_parent”
        android:layout_height=”fill_parent” >
    </ExpandableListView>

</RelativeLayout>

Create group_item.xml file and this xml layout is for Expandable ListView Group’s
file : group_item.xml
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
    xmlns:android=”http://schemas.android.com/apk/res/android”
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”
    android:orientation=”vertical”
    android:padding=”10dp” >

    <TextView
        android:id=”@+id/group_name”
        android:layout_width=”wrap_content”
        android:layout_height=”wrap_content”
        android:paddingLeft=”25dp”
        android:textSize=”25dp” />

</LinearLayout>

Create group_item.xml file and this xml layout is for Expandable ListView Children’s
file : child_item.xml
<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout
    xmlns:android=”http://schemas.android.com/apk/res/android”
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”
    android:paddingTop=”4dp”
    android:paddingBottom=”4dp”
    android:layout_marginLeft=”50dp”>

    <TextView
        android:id=”@+id/country_name”
        android:layout_width=”wrap_content”
        android:layout_height=”wrap_content”
        android:layout_alignBottom=”@+id/flag”
        android:layout_marginBottom=”14dp”
        android:layout_marginLeft=”29dp”
        android:layout_toRightOf=”@+id/flag”
        android:text=”TextView”
        android:textSize=”20dp” />

    <com.android.volley.toolbox.NetworkImageView
        android:id=”@+id/flag”
        android:layout_width=”70dp”
        android:layout_height=”40dp”
        android:layout_alignParentLeft=”true”
        android:layout_alignParentTop=”true”
        android:layout_marginLeft=”27dp”
        android:src=”@drawable/ic_launcher” />

</RelativeLayout>

Application Object

Create a class MyApplication which extends Application ,this application object represents singleton pattern , the purpose of this class is make volley request available  through out of the application

  1. The getInstance method of application class returns application object.
  2. The getReqQueue method returns the RequestQueue object
  3. Inside addToReqQueue method we are adding calling add() method upon RequestObject and passing request as paramter to it .
  4. Inside getImageLoader method were we are calling to a constructor of ImageLoader Class by passing requestQueue object and BitmapLruCache object as parameter.

file : MyApplication.java

package com.pavan.expandablelistdemo;

import android.app.Application;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class MyApplication extends Application {

    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static MyApplication mInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized MyApplication getInstance() {
        return mInstance;
    }

    public RequestQueue getReqQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }

        return mRequestQueue;
    }

    public <T> void addToReqQueue(Request<T> req, String tag) {

        getReqQueue().add(req);
    }

    public <T> void addToReqQueue(Request<T> req) {

        getReqQueue().add(req);
    }

    public ImageLoader getImageLoader() {
        getReqQueue();
        if (mImageLoader == null) {
            mImageLoader = new ImageLoader(this.mRequestQueue,
                    new BitmapLruCache());
        }
        return this.mImageLoader;
    }

    public void cancelPendingReq(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

Now inside your manifest file for application tag set the android:name attribute with fully qualified path of the above defined class.

<application
    android:name=”com.pavan.expandablelistdemo.MyApplication”
    ——————————————-
    ——————————————-
    >

BitMap Cache

Create a class BitmapLruCache which extends LruCache and override the required method as this class is used for caching the image

file :BitmapLruCache.java

package com.pavan.expandablelistdemo;

import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.toolbox.ImageLoader.ImageCache;

public class BitmapLruCache extends LruCache<String, Bitmap> implements
        ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        return cacheSize;
    }

    public BitmapLruCache() {
        this(getDefaultLruCacheSize());
    }

    public BitmapLruCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }

    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}

Model For Group And Child

Create a model class Group inside your application package , and add getter’s and setter’s method for the variable’s of this class to accessing the group data .
file : Group.java
package com.pavan.expandablelistdemo;

import java.util.ArrayList;

public class Group {

    private String Name;
    private ArrayList<Child> Items;

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        this.Name = name;
    }

    public ArrayList<Child> getItems() {
        return Items;
    }

    public void setItems(ArrayList<Child> Items) {
        this.Items = Items;
    }

}

Create a model class child inside your application package , and add getter’s and setter’s method for the variable’s of this class to accessing the child data
file : Child.java
package com.pavan.expandablelistdemo;

public class Child {

    private String Name;
    private int Image;

    public String getName() {
        return Name;
    }

    public void setName(String Name) {
        this.Name = Name;
    }

    public int getImage() {
        return Image;
    }

    public void setImage(int Image) {
        this.Image = Image;
    }
}

Adapter

Create a class ExpandableListAdapter which extends BaseExpandableListAdapter to populate items associated with this view. this class provides two important methods which returns view object used for rendering group and child items .
  1.     getGroupView() – Returns view for the list group item .
  2.     getChildView() – Returns view for list child item .

file : ExpandListAdapter.java

package com.pavan.expandablelistdemo;

import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;

public class ExpandListAdapter extends BaseExpandableListAdapter {

    private Context context;
    private ArrayList<Group> groups;

    ImageLoader imageLoader = MyApplication.getInstance().getImageLoader();

    public ExpandListAdapter(Context context, ArrayList<Group> groups) {
        this.context = context;
        this.groups = groups;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        ArrayList<Child> chList = groups.get(groupPosition).getItems();
        return chList.get(childPosition);
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {

        Child child = (Child) getChild(groupPosition, childPosition);
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) context
                    .getSystemService(context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.child_item, null);
        }

        if (imageLoader == null)
            imageLoader = MyApplication.getInstance().getImageLoader();

        TextView tv = (TextView) convertView.findViewById(R.id.country_name);
        NetworkImageView iv = (NetworkImageView) convertView
                .findViewById(R.id.flag);

        tv.setText(child.getName().toString());
        iv.setImageUrl(child.getImage(), imageLoader);

        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        ArrayList<Child> chList = groups.get(groupPosition).getItems();
        return chList.size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return groups.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return groups.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        Group group = (Group) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater inf = (LayoutInflater) context
                    .getSystemService(context.LAYOUT_INFLATER_SERVICE);
            convertView = inf.inflate(R.layout.group_item, null);
        }
        TextView tv = (TextView) convertView.findViewById(R.id.group_name);
        tv.setText(group.getName());
        return convertView;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

}

Main Activity

  1. Create a class MainActivty which extends Activity and set the content of this activity with the above defined xml layout (activity_main.xml) file , this is the activity which contains expandable list view .
  2. Inside the makejsonobjreq() method make for jsonobject request and parse the json data and construct the expandable listview.

file : MainActivity.java

package com.pavan.expandablelistdemo;

import java.util.ArrayList;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.widget.ExpandableListView;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;

public class MainActivity extends Activity {
    String url = “http://api.tutorialsbuzz.com/cricketworldcup2015/cricket.json”;
    ProgressDialog PD;

    private ExpandListAdapter ExpAdapter;
    private ExpandableListView ExpandList;

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

        ExpandList = (ExpandableListView) findViewById(R.id.exp_list);

        PD = new ProgressDialog(this);
        PD.setMessage(“Loading…..”);
        PD.setCancelable(false);

        makejsonobjreq();
    }

    private void makejsonobjreq() {
        PD.show();

        JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET, url,
                null, new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        ArrayList<Group> list = new ArrayList<Group>();
                        ArrayList<Child> ch_list;

                        try {
                            Iterator<String> key = response.keys();
                            while (key.hasNext()) {
                                String k = key.next();

                                Group gru = new Group();
                                gru.setName(k);
                                ch_list = new ArrayList<Child>();

                                JSONArray ja = response.getJSONArray(k);

                                for (int i = 0; i < ja.length(); i++) {

                                    JSONObject jo = ja.getJSONObject(i);

                                    Child ch = new Child();
                                    ch.setName(jo.getString(“name”));
                                    ch.setImage(jo.getString(“flag”));

                                    ch_list.add(ch);
                                } // for loop end
                                gru.setItems(ch_list);
                                list.add(gru);
                            } // while loop end

                            ExpAdapter = new ExpandListAdapter(
                                    MainActivity.this, list);
                            ExpandList.setAdapter(ExpAdapter);

                            PD.dismiss();

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        PD.dismiss();
                    }
                });
        MyApplication.getInstance().addToReqQueue(jsonObjReq, “jreq”);
    }
}

  • Hi Pawan canu like to provide pup script of above json …

  • Hi ….can u provide a php script for above API….

  • You forgot to mention that to use the singleton pattern, you need to add:

    <application
    android:name="com.your.MyApplication"

    to AndroidManifest.xml

  • @Jeff Rebeiro

    Thank you i have updated the posted

  • I am getting error at MyApplication.getInstance().addToReqQueue(jsonObjReq, "jreq");
    please help me

  • how to get jo.getString("name") on setOnChildClickListener? can you help me please?

  • i have a question, how to implement onClick on Child ??
    thank's

  • @Ricardo
    Make sure whether you have add the application class to manifest file

  • Hi, am getting blank screen after loading, Can u help me

  • Hi Pawan Deshpande

    http://api.tutorialsbuzz.com/cricketworldcup2015/cricket.json
    the above link is not working. It does not show any result.

  • Hi Hasnain
    Thank u for reporting ,link is working now

  • Man, this is a great tutorial. However, the link: "http://api.tutorialsbuzz.com/cricketworldcup2015/cricket.json&quot; is not working. Thus its very difficult to test it. Please help or please notify me of a another api location.

    Thanks much!

  • Thanks you – the api is up. But I am seeing a blank page, would you be able to help?

  • Hello sir. Am getting blank screen after loading, Can u help me please.
    geomenda@yahoo.com

  • @Geoffrey
    Make sure you have added internet permission in manifest file and while running make sure internet is enabled in your device

  • Am getting blank screen after loading, Can u help me please.
    geomenda@yahoo.com

  • Man, this is a great tutorial. However, the link: "http://api.tutorialsbuzz.com/cricketworldcup2015/cricket.json&quot; is not working. Thus its very difficult to test it. Please help or please notify me of a another api location.

    Thanks much!

  • @john smith
    Thanks for notifying issue , Now Url is up and running you can test

  • inside the ExpandListAdapter class, an error is reporting where iv.setImageUrl(child.getImage(), imageLoader);
    you are trying to pass in an integer "getImage()" where setImageURL is expecting a string. Any idea what is meant to be happening here?

  • Hi, I have a question.
    How to get value on click event for group as well as child items?

  • Hi, I Have a question..
    How to sort json data (group) ??

  • Url not working,it is really hard to test

  • Hi,
    Please send me code, url is not working.
    meghashine22@gmail.com

  • The all child items is displayed inside all parent items what to do for separating this item

  • aya mohammed

    How to sort json data (group) ?

  • Hafizudin Johari

    Hi. can you update the link of JSON file provided again. The link is not working now. thanks

  • iman hoshmand

    Hi pawan
    who download file json example for tutarial???
    plz send file cricket.json
    or send file email me
    imanhoshmand@gmail.com

  • Vladimir

    I created cricket.json. You can download from here:
    http://jsoneditoronline.org/?id=2a0ffc45c0a7e9d7e506a9bff4a33aas
    You must press Save>>Save to disk

  • Sunny Kumar

    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method ‘void com.hewtechsystem.expendablelistviewjsondata.MyApplication.addToReqQueue(com.android.volley.Request, java.lang.String)’ on a null object reference
    at com.hewtechsystem.expendablelistviewjsondata.MainActivity.makejsonobjreq(MainActivity.java:104)