About Francesco Azzola

I'm a senior software engineer with more than 15 yrs old experience in JEE architecture. I'm SCEA certified (Sun Certified Enterprise Architect), SCWCD, SCJP. I'm an android enthusiast and i've worked for long time in the mobile development field.

Android ListView: Endless adapter

This post explains how to create an endless adapter for a ListView. An endless adapter is an adapter that loads more data when user reaches the ListView end. This kind of adapter is useful when there is a large number of items and we don’t want to show them all to avoid a long loading time. To achieve this goal we will create:

  • a custom listview
  • a listener
  • a custom adapter

 
In this case the custom adapter is very simple and we can replace it with something more complex or use standard android adapter.

android_endless_adapter[5]

Custom Endless ListView component

This is the main component, that holds the business logic. In this component we have to find a way to check if the user scrolled all the item inside the ListView and we reached its end. The first step is creating a custom component so we can extend the standard ListView behavior.

public class EndlessListView extends ListView implements OnScrollListener {
..
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        ...
        }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {}

}

At line 1, we extends ListView and implements OnScrollListener to get notified when user scrolls the time on the ListView. At line 4, we override onScroll method, called during the scroll. When we reach the ListView end we have to show a view that informs the user to wait until the all data is loaded. We can use a “trick” to show the wait indicator, we can exploit the ListView footer. We can add and remove it as we need. To make our component configurable we can simply set a view to use a footer:

public void setLoadingView(int resId) {
    LayoutInflater inflater = (LayoutInflater) super.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    footer = (View) inflater.inflate(resId, null);
    this.addFooterView(footer);

}

Let’s focus on the onScroll method. Here we have to check if the firstVisibleElement plus itemCounts (the number of items show inside the ListView) is greater that the total number of items. If this condition is verified then we can fire the event to load more data:

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {

    if (getAdapter() == null)
        return ;

    if (getAdapter().getCount() == 0)
        return ;

    int l = visibleItemCount + firstVisibleItem;
    if (l >= totalItemCount && !isLoading) {
        // It is time to add new data. We call the listener
        this.addFooterView(footer);
        isLoading = true;
        listener.loadData();
    }
}

At line 12, we simply add the footer to inform the user we are loading more data, then at line 13 we set a true a boolean attribute to not fire the event again while we are still loading the data and then we call the listener.

As you can see the listener is very simple:

public static interface EndlessListener {
    public void loadData() ;
}

Just one more thing, when the loading data process is finished our custom ListView must be informed so that we can refresh the items and remove the footer:

public void addNewData(List<String> data) {
    this.removeFooterView(footer);
    adapter.addAll(data);
    adapter.notifyDataSetChanged();
    isLoading = false;
}

At line 4, we call notifyDataSetChanged to inform the adapter that the dataset is changed.

Test custom component

To test the custom component we can create a simple layout including our custom ListView:

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <com.survivingwithandroid.endlessadapter.EndlessListView android:id="@+id/el"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"  />

</RelativeLayout>

and we need a main activity so that :

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

    lv = (EndlessListView) findViewById(R.id.el);
    EndlessAdapter adp = new EndlessAdapter(this, createItems(mult), R.layout.row_layout);
    lv.setLoadingView(R.layout.loading_layout);
    lv.setAdapter(adp);
    lv.setListener(this);

}

At line 7, we set the footer view then at line the adapter and at the end we set our activity as a listener for our custom ListView. To emulate the internet loading data, we can simply create an AsyncTask and make our thread sleeps for some seconds. Notice that in the onPostExecute:

@Override
protected void onPostExecute(List<String> result) {            
    super.onPostExecute(result);
    lv.addNewData(result);
}

At line 4, we add the new loaded data.

Source code available @ github.

 

Reference: Android ListView: Endless adapter from our JCG partner Francesco Azzola at the Surviving w/ Android blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

3 Responses to "Android ListView: Endless adapter"

  1. Timur says:

    I try start this code but it fall.

    public void addNewData(List data) {
    on line : adapter.addAll(data);

    My log:
    10-22 14:46:38.918: D/AndroidRuntime(566): Shutting down VM
    10-22 14:46:38.918: W/dalvikvm(566): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
    10-22 14:46:38.939: E/AndroidRuntime(566): FATAL EXCEPTION: main
    10-22 14:46:38.939: E/AndroidRuntime(566): java.lang.NoSuchMethodError: com.example.test_whithoutendadapter.EndlessAdapter.addAll
    10-22 14:46:38.939: E/AndroidRuntime(566): at com.example.test_whithoutendadapter.EndlessListView.addNewData(EndlessListView.java:92)
    10-22 14:46:38.939: E/AndroidRuntime(566): at com.example.test_whithoutendadapter.MainActivity$FakeNetLoader.onPostExecute(MainActivity.java:59)
    10-22 14:46:38.939: E/AndroidRuntime(566): at com.example.test_whithoutendadapter.MainActivity$FakeNetLoader.onPostExecute(MainActivity.java:1)
    10-22 14:46:38.939: E/AndroidRuntime(566): at android.os.AsyncTask.finish(AsyncTask.java:417)
    10-22 14:46:38.939: E/AndroidRuntime(566): at android.os.AsyncTask.access$300(AsyncTask.java:127)
    10-22 14:46:38.939: E/AndroidRuntime(566): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
    10-22 14:46:38.939: E/AndroidRuntime(566): at android.os.Handler.dispatchMessage(Handler.java:99)
    10-22 14:46:38.939: E/AndroidRuntime(566): at android.os.Looper.loop(Looper.java:123)
    10-22 14:46:38.939: E/AndroidRuntime(566): at android.app.ActivityThread.main(ActivityThread.java:4627)
    10-22 14:46:38.939: E/AndroidRuntime(566): at java.lang.reflect.Method.invokeNative(Native Method)
    10-22 14:46:38.939: E/AndroidRuntime(566): at java.lang.reflect.Method.invoke(Method.java:521)
    10-22 14:46:38.939: E/AndroidRuntime(566): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    10-22 14:46:38.939: E/AndroidRuntime(566): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    10-22 14:46:38.939: E/AndroidRuntime(566): at dalvik.system.NativeStart.main(Native Method)

  2. Dev says:

    This code works perfect !
    .

    How to work with the collection type ……. ArrayList<HashMap>
    .
    I am not able to convert this example this this collection type
    .
    Is it possible ? … if so how ?

Leave a Reply


2 − = zero



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close