In this tutorial i am discussing about adding load more functionality to listview. It will be useful when you want to show data into paged format instead of loading huge amount of data into listview.

Download Code

Paged XML data

For this tutorial i am accessing an url which will give you paged XML by taking page number. Each page contains 20 results. You can access the xml by accessing url https://api.androidhive.info/list_paging/?page=1. This url accepts “page” (page number – 1, 2, 3 ..) parameter as a GET variable. The sample response will be

<menu>
  <item>
     <id>1</id>
     <name>sample list data 1</name>
  </item>
  <item>
     <id>2</id>
     <name>sample list data 2</name>
  </item>
  .
  .
  .
  <item>
     <id>20</id>
     <name>sample list data 20</name>
  </item>
<item>

You can prepare your own json or xml data with paging option. Example like displaying mysql data by taking page number.

Adding button to ListView at the bottom

You can add a view at the bottom of the listview by using addFooterView method. In this tutorial i am adding a button to the bottom of the listview.

// Getting listview from xml
ListView lv = (ListView) findViewById(R.id.list);

// Creating a button - Load More
Button btnLoadMore = new Button(this);
btnLoadMore.setText("Load More");

// Adding button to listview at footer
lv.addFooterView(btnLoadMore);

Running a Asynchronous Background Thread

We need a background thread while sending http request in order to get new data for listview. Following is a example of Async Background task.

private class YourBackgroundThreadName extends AsyncTask<Void, Void, Void> {

		@Override
		protected void onPreExecute() {
		   // Before starting background task
		   // Show Progress Dialog etc,.
		}

		protected Void doInBackground(Void... unused) {
			runOnUiThread(new Runnable() {
				public void run() {
                // Run actual background task
                // Like sending HTTP Request - Parsing data
				}
			});
			return (null);
		}

		protected void onPostExecute(Void unused) {
			// On completing background task
			// closing progress dialog etc,.
		}

Calling a background thread

// calling a background task
new YourBackgroundThreadName().execute();

Create new Project

1. Create a new project by going to File ⇒ New ⇒ Android Project and fill all the required details.
2. Open your main.xml and add a listview element in it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

3. Create a new XML layout for single list row item under layouts folder.
Right Click on res ⇒ New ⇒ Android XML File and fill with following code. Name the xml file as list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">  

        <!-- List item name -->
        <TextView
            android:id="@+id/name"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textColor="#acacac"
            android:textStyle="bold"
            android:gravity="left"
            android:padding="10dip"
            android:textSize="16dp">
        </TextView>
</LinearLayout>

4. Create a new class and name it as ListViewAdapter.java and fill with following code. This class is required to fill the listview with parsed xml data. I just displayed single text view.

package com.example.androidhive;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ListViewAdapter extends BaseAdapter {

    private Activity activity;
    private ArrayList<HashMap<String, String>> data;
    private static LayoutInflater inflater=null;

    public ListViewAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
        activity = a;
        data=d;
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public int getCount() {
        return data.size();
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;
        if(convertView==null)
            vi = inflater.inflate(R.layout.list_item, null);

        TextView name = (TextView)vi.findViewById(R.id.name);

        HashMap<String, String> item = new HashMap<String, String>();
        item = data.get(position);

        //Setting all values in listview
        name.setText(item.get("name"));
        return vi;
    }
}

5. Now open your MainActivity try the following code. In the following code i am just displaying data into listview by parsing XML. Finally i added a load more button to the bottom to listview

public class AndroidListViewWithLoadMoreButtonActivity extends Activity {

	// All variables
	XMLParser parser;
	Document doc;
	String xml;
	ListView lv;
	ListViewAdapter adapter;
	ArrayList<HashMap<String, String>> menuItems;
	ProgressDialog pDialog;

	private String URL = "https://api.androidhive.info/list_paging/?page=1";

	// XML node keys
	static final String KEY_ITEM = "item"; // parent node
	static final String KEY_ID = "id";
	static final String KEY_NAME = "name";

	// Flag for current page
	int current_page = 1;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		lv = (ListView) findViewById(R.id.list);

		menuItems = new ArrayList<HashMap<String, String>>();

		parser = new XMLParser();
		xml = parser.getXmlFromUrl(URL); // getting XML
		doc = parser.getDomElement(xml); // getting DOM element

		NodeList nl = doc.getElementsByTagName(KEY_ITEM);
		// looping through all item nodes <item>
		for (int i = 0; i < nl.getLength(); i++) {
			// creating new HashMap
			HashMap<String, String> map = new HashMap<String, String>();
			Element e = (Element) nl.item(i);
			// adding each child node to HashMap key => value
			map.put(KEY_ID, parser.getValue(e, KEY_ID)); // id not using any where
			map.put(KEY_NAME, parser.getValue(e, KEY_NAME));

			// adding HashList to ArrayList
			menuItems.add(map);
		}

		// LoadMore button
		Button btnLoadMore = new Button(this);
		btnLoadMore.setText("Load More");

		// Adding Load More button to lisview at bottom
		lv.addFooterView(btnLoadMore);

		// Getting adapter
		adapter = new ListViewAdapter(this, menuItems);
		lv.setAdapter(adapter);
	}
}
android listview with load more button

Working with Load More Button

Until now we displayed a simple listview with the first paged xml data. Now we need to add functionality to load more button. Add a click event listener to load more button and call a background thread which will append next paged data to listview.

Appending data to listview is nothing but appending data into adapter array. If you write your own Custom Adapter you need to call notifyDataSetChanged() on the adapter class in order to refresh list view. (For reference check this question: Dynamic ListView in Android app)

6. Add a click event listener to LoadMore button in your MainActivity Class and start a new background thread once it is clicked.

/**
* Listening to Load More button click event
* */
btnLoadMore.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View arg0) {
		// Starting a new async task
		new loadMoreListView().execute();
	}
});

7. Now after closing onCreate Method write a background thread class like below. In the following code i am making a HTTP request with next page number. After getting the new paged data i am parsing it and loading into listview. Once the listview is appended with new data i am setting scroll position using setSelectionFromTop() method.

	/**
	 * Async Task that send a request to url
	 * Gets new list view data
	 * Appends to list view
	 * */
	private class loadMoreListView extends AsyncTask<Void, Void, Void> {

		@Override
		protected void onPreExecute() {
			// Showing progress dialog before sending http request
			pDialog = new ProgressDialog(
					AndroidListViewWithLoadMoreButtonActivity.this);
			pDialog.setMessage("Please wait..");
			pDialog.setIndeterminate(true);
			pDialog.setCancelable(false);
			pDialog.show();
		}

		protected Void doInBackground(Void... unused) {
			runOnUiThread(new Runnable() {
				public void run() {
					// increment current page
					current_page += 1;

					// Next page request
					URL = "https://api.androidhive.info/list_paging/?page=" + current_page;

					xml = parser.getXmlFromUrl(URL); // getting XML
					doc = parser.getDomElement(xml); // getting DOM element

					NodeList nl = doc.getElementsByTagName(KEY_ITEM);
					// looping through all item nodes <item>
					for (int i = 0; i < nl.getLength(); i++) {
						// creating new HashMap
						HashMap<String, String> map = new HashMap<String, String>();
						Element e = (Element) nl.item(i);

						// adding each child node to HashMap key => value
						map.put(KEY_ID, parser.getValue(e, KEY_ID));
						map.put(KEY_NAME, parser.getValue(e, KEY_NAME));

						// adding HashList to ArrayList
						menuItems.add(map);
					}

					// get listview current position - used to maintain scroll position
					int currentPosition = lv.getFirstVisiblePosition();

					// Appending new data to menuItems ArrayList
					adapter = new ListViewAdapter(
							AndroidListViewWithLoadMoreButtonActivity.this,
							menuItems);

					// Setting new scroll position
					lv.setSelectionFromTop(currentPosition + 1, 0);
				}
			});
			return (null);
		}		

		protected void onPostExecute(Void unused) {
			// closing progress dialog
			pDialog.dismiss();
		}
	}

Final Code

The final code of the MainActivity class is

package com.example.androidhive;

import java.util.ArrayList;
import java.util.HashMap;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

public class AndroidListViewWithLoadMoreButtonActivity extends Activity {

	// All variables
	XMLParser parser;
	Document doc;
	String xml;
	ListView lv;
	ListViewAdapter adapter;
	ArrayList<HashMap<String, String>> menuItems;
	ProgressDialog pDialog;

	private String URL = "https://api.androidhive.info/list_paging/?page=1";

	// XML node keys
	static final String KEY_ITEM = "item"; // parent node
	static final String KEY_ID = "id";
	static final String KEY_NAME = "name";

	// Flag for current page
	int current_page = 1;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		lv = (ListView) findViewById(R.id.list);

		menuItems = new ArrayList<HashMap<String, String>>();

		parser = new XMLParser();
		xml = parser.getXmlFromUrl(URL); // getting XML
		doc = parser.getDomElement(xml); // getting DOM element

		NodeList nl = doc.getElementsByTagName(KEY_ITEM);
		// looping through all item nodes <item>
		for (int i = 0; i < nl.getLength(); i++) {
			// creating new HashMap
			HashMap<String, String> map = new HashMap<String, String>();
			Element e = (Element) nl.item(i);
			// adding each child node to HashMap key => value
			map.put(KEY_ID, parser.getValue(e, KEY_ID)); // id not using any where
			map.put(KEY_NAME, parser.getValue(e, KEY_NAME));

			// adding HashList to ArrayList
			menuItems.add(map);
		}

		// LoadMore button
		Button btnLoadMore = new Button(this);
		btnLoadMore.setText("Load More");

		// Adding Load More button to lisview at bottom
		lv.addFooterView(btnLoadMore);

		// Getting adapter
		adapter = new ListViewAdapter(this, menuItems);
		lv.setAdapter(adapter);

		/**
		 * Listening to Load More button click event
		 * */
		btnLoadMore.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// Starting a new async task
				new loadMoreListView().execute();
			}
		});

		/**
		 * Listening to listview single row selected
		 * **/
		lv.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				// getting values from selected ListItem
				String name = ((TextView) view.findViewById(R.id.name))
						.getText().toString();

				// Starting new intent
				Intent in = new Intent(getApplicationContext(),
						SingleMenuItemActivity.class);
				in.putExtra(KEY_NAME, name);
				startActivity(in);
			}
		});
	}

	/**
	 * Async Task that send a request to url
	 * Gets new list view data
	 * Appends to list view
	 * */
	private class loadMoreListView extends AsyncTask<Void, Void, Void> {

		@Override
		protected void onPreExecute() {
			// Showing progress dialog before sending http request
			pDialog = new ProgressDialog(
					AndroidListViewWithLoadMoreButtonActivity.this);
			pDialog.setMessage("Please wait..");
			pDialog.setIndeterminate(true);
			pDialog.setCancelable(false);
			pDialog.show();
		}

		protected Void doInBackground(Void... unused) {
			runOnUiThread(new Runnable() {
				public void run() {
					// increment current page
					current_page += 1;

					// Next page request
					URL = "https://api.androidhive.info/list_paging/?page=" + current_page;

					xml = parser.getXmlFromUrl(URL); // getting XML
					doc = parser.getDomElement(xml); // getting DOM element

					NodeList nl = doc.getElementsByTagName(KEY_ITEM);
					// looping through all item nodes <item>
					for (int i = 0; i < nl.getLength(); i++) {
						// creating new HashMap
						HashMap<String, String> map = new HashMap<String, String>();
						Element e = (Element) nl.item(i);

						// adding each child node to HashMap key => value
						map.put(KEY_ID, parser.getValue(e, KEY_ID));
						map.put(KEY_NAME, parser.getValue(e, KEY_NAME));

						// adding HashList to ArrayList
						menuItems.add(map);
					}

					// get listview current position - used to maintain scroll position
					int currentPosition = lv.getFirstVisiblePosition();

					// Appending new data to menuItems ArrayList
					adapter = new ListViewAdapter(
							AndroidListViewWithLoadMoreButtonActivity.this,
							menuItems);
					lv.setAdapter(adapter);
					// Setting new scroll position
					lv.setSelectionFromTop(currentPosition + 1, 0);

				}
			});

			return (null);
		}

		protected void onPostExecute(Void unused) {
			// closing progress dialog
			pDialog.dismiss();
		}
	}
}

Other Classes needed in this project

XMLParser.java – needed to parse xml data

package com.example.androidhive;

import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import android.util.Log;

public class XMLParser {

	// constructor
	public XMLParser() {

	}

	/**
	 * Getting XML from URL making HTTP request
	 * @param url string
	 * */
	public String getXmlFromUrl(String url) {
		String xml = null;

		try {
			// defaultHttpClient
			DefaultHttpClient httpClient = new DefaultHttpClient();
			HttpPost httpPost = new HttpPost(url);

			HttpResponse httpResponse = httpClient.execute(httpPost);
			HttpEntity httpEntity = httpResponse.getEntity();
			xml = EntityUtils.toString(httpEntity);

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// return XML
		return xml;
	}

	/**
	 * Getting XML DOM element
	 * @param XML string
	 * */
	public Document getDomElement(String xml){
		Document doc = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {

			DocumentBuilder db = dbf.newDocumentBuilder();

			InputSource is = new InputSource();
		        is.setCharacterStream(new StringReader(xml));
		        doc = db.parse(is); 

			} catch (ParserConfigurationException e) {
				Log.e("Error: ", e.getMessage());
				return null;
			} catch (SAXException e) {
				Log.e("Error: ", e.getMessage());
	            return null;
			} catch (IOException e) {
				Log.e("Error: ", e.getMessage());
				return null;
			}

	        return doc;
	}

	/** Getting node value
	  * @param elem element
	  */
	 public final String getElementValue( Node elem ) {
	     Node child;
	     if( elem != null){
	         if (elem.hasChildNodes()){
	             for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){
	                 if( child.getNodeType() == Node.TEXT_NODE  ){
	                     return child.getNodeValue();
	                 }
	             }
	         }
	     }
	     return "";
	 }

	 /**
	  * Getting node value
	  * @param Element node
	  * @param key string
	  * */
	 public String getValue(Element item, String str) {
			NodeList n = item.getElementsByTagName(str);
			return this.getElementValue(n.item(0));
		}
}
This image is for thumbnail purpose.
android listview with load more button
Ravi is hardcore Android programmer and Android programming has been his passion since he compiled his first hello-world program. Solving real problems of Android developers through tutorials has always been interesting part for him.
  • Nice tutorial.

  • Thet Paing

    I want to add previous and next button in your application like this link http://stackoverflow.com/questions/15376995/getting-next-and-previous-detail-data-from-listview I want to full tutorial. thanks brother

    • Thet Paing

      Now, I finished my request tutorial. Thanks your tutorial ……..

  • sKoyce

    i think you have to use for this tutorial with JsonParser

    • Sumeet Rathore

      have you got the answer how do it with JSONParser please help me..

      • Rekz

        This is how I did it, I used HttpClient in a AsyncTask to get the JSON. Once you have the JSON string, use JSON reader API (JSONObject etc) to load you separate fields into arraylist. The rest you do it like he did it. I hope that helps

  • Great example!!!!! You save the day! Thanks a lot!

  • andriangungon

    sir the application has error when I changed the minimum sdk at 10 or above in android manifest. Please help sir. Thanks!

    10-03 13:00:10.944: E/AndroidRuntime(2499): FATAL EXCEPTION: main
    10-03 13:00:10.944: E/AndroidRuntime(2499): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.androidhive/com.example.androidhive.MainActivity}: android.os.NetworkOnMainThreadException

    • This is old tutorial. Try keeping all network calls code in Async Task

  • andriangungon

    great tutorial sir. I changed to asynctask onload and my problem is the dialog box is not showing. Please help sir. Thanks in advanced.

    here is the code sir:

    private class loadVideos extends AsyncTask {
    protected void onPreExecute() {
    pDialog = new ProgressDialog(MainActivity.this);
    pDialog.setMessage(“Please wait..”);
    pDialog.setIndeterminate(true);
    pDialog.setCancelable(false);
    pDialog.show();
    }

    protected Void doInBackground(Void… unused) {

    runOnUiThread(new Runnable() {
    public void run() {
    list = (ListView) findViewById(R.id.list);
    menuItems = new ArrayList<HashMap>();
    parser = new XMLParser();
    xml = parser.getXmlFromUrl(URL); // getting XML
    doc = parser.getDomElement(xml); // getting DOM element
    NodeList nl = doc.getElementsByTagName(KEY_ITEM);
    // looping through all item nodes

    for (int i = 0; i < nl.getLength(); i++) {
    HashMap map = new HashMap();
    Element e = (Element) nl.item(i);
    map.put(KEY_ID, parser.getValue(e, KEY_ID)); // id not using any where
    map.put(KEY_NAME, parser.getValue(e, KEY_NAME));
    map.put(KEY_VIEWS, parser.getValue(e, KEY_VIEWS));
    map.put(KEY_THUMB_URL, parser.getValue(e, KEY_THUMB_URL));
    menuItems.add(map);
    }

    adapter = new ListViewAdapter(MainActivity.this, menuItems);
    list.setAdapter(adapter);
    }

    });

    return (null);
    }

    protected void onPostExecute(Void unused) {

    // closing progress dialog

    pDialog.dismiss();

    }

    }

  • andriangungon

    sir when i removed runOnUIThread, I got an error, please help sir I newbie in android dev. Thanks sir.

  • andriangungon

    finally I got it sir…

  • andriangungon

    sir there’s an error when all the data has been loaded. I got an error when i click again the loadmore. How to check sir if all the data are loaded already? Please help sir. thanks! more power!

  • andriangungon

    Yeah! I also learned a lot from this website! The best!

  • Rupesh

    Sir i followed your tutorials and its really working very well, I only
    have one question on how to add load more function on Scroll moving. Please
    consider me. Thanks.

  • imran RP

    good example thank you ,, it is usefull for me.

  • george

    Hi all. I am a novice in developing app and thanks to
    Ravi for all good work that is doing . I’m working at a simple app and I get
    stuck . if you have knowledge of
    building android apps, and make team
    with me please replay to george.celsie@gmail.com . Thanks ang
    good luck for all your projects.

  • Afifatul M

    HI GOEIHIONGKUEK, could u tell me how to mix it with json? I have no idea about how to create paging in mysql database. 🙁

  • Sruthi

    Hi,
    This looks good, but where are you removing the load more button once the list is completly loaded? Can you provide the snippet for that?

  • sruthi

    Hi,
    This looks good, but where are you removing the load more button once the list has reached the end? Can you provide the snippet for that?

  • Qb Dudez

    have you figure out the solution? i also want to append the new data

  • Sumeet Rathore

    how to do it with JSON Parser please help me out ??

  • phan piseth

    how to do with JSON?

  • phan piseth

    can you show your this web service?

  • Ram Chandran

    Wow, it’s working fine. Thanks

  • Sonu Kunwar

    hi ravi …………..i m getting error on this ,not even option coming to import this class DefaulthttpClient ….i m trying to doing this project in android studio.

    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(url);

    HttpResponse httpResponse = httpClient.execute(httpPost);
    HttpEntity httpEntity = httpResponse.getEntity();
    is = httpEntity.getContent();

  • Arslanali

    Hello, you have php files?

  • Arslanali

    Hello Ravi. You could not put you php file in “download code”?

  • Omis

    Hi Ravi , I tried your code but I found a problem , this one is when I press the Load more button the listview contains the new list of items not the old one plus the new data , it’s like the items are removed and be replaced by the new ones , how can I fix this ?

  • Lhufi Luthfi

    Android ListView with Load More Button for json ?

  • Hafiz Oktri Putra

    can you tell any way to parse the paging if I use these json objects?

    “paginator”: {
    “total_items”: 5007,
    “total_pages”: 501,
    “items_per_page”: 10,
    “current_page”: 1,
    “items_start”: 1,
    “items_end”: 10
    },

    I want to make the the “current_page” change when I press the Load More button