We'll create a lazily loaded ListView. That is , as the user scrolls and nears the end of the list, we'll append more data to the ListView.
This is how its going to look like :
To do this, we have 4 components :
So here's the code. :
MainActivity.java
In the onCreate() method, we create a ListView, set an adapter to it AND set an OnScrollListener. The scrollListener's loadMore() method is called when the ListView is nearing its end and needs more data.
In loadMore(), an AsyncTask fetches more data and appends it to the ListView.
Here's the Magical OnScrollListener :
LazyLoader.java
The onScroll() method of the onScrollListener is called when the user scrolls the ListView.
In this method, we do calculations to check if the List is nearing its end. If yes, the loadMore() method is called. We have implemented the loadMore() method in the MainActivity, which will append the ListView with more data.
Here's the FetchItemsTask, if you're interested :
FetchItemsTask.java
The ResponseListener :
I've broken some coding conventions for the sake of simplicity. You can find the proper, full source code at Github :) .
This is how its going to look like :
To do this, we have 4 components :
- MainActivity - The Activity of course !
- FetchItemsTask - An AsyncTask to load fresh data in the background.
- ResponseListener - Interface for the AsyncTask to return the fresh data back to the Activity.
- LazyLoader - The Main Component !! Basically an OnScrollListener . When the List is scrolled, this listener does some basic calculations to check if the user is nearing the end of the List. If yes, then a loadMore() method is called.
So here's the code. :
MainActivity.java
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.ViewGroup.LayoutParams; import android.widget.AbsListView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.ProgressBar; import java.util.List; public class MainActivity extends AppCompatActivity { private ArrayAdapter<String> adapter ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // create the ListView ListView listView = new ListView(this); // add a ProgressBar as ListView's footer to indicate data load listView.addFooterView(new ProgressBar(this)); // create an adapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1); // plug the adapter to the ListView listView.setAdapter(adapter); // set the ListView as the activity's content setContentView(listView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); // CRUCIAL PART !! Add the LazyLoader as the onScrollListener for the ListView. listView.setOnScrollListener(new LazyLoader() { // This method is called when the user is nearing the end of the ListView // and the ListView is ready to add more items. @Override public void loadMore(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // The ListView needs more data. So Fetch !! loadItems(); } }); } // Called by the LazyLoader when the ListView is ready for fresh data. private void loadItems() { // Index is required to fetch the next set of items int startIndex = adapter.getCount(); // Fetch more items Asynchronously. new FetchItemsTask(startIndex, responseListener).execute(); } // The FetchItemsTask delivers the new data to this listener in the main thread. private ResponseListener responseListener = new ResponseListener() { @Override public void onResponse(List<String> newItems) { // append the fresh data to the ListView. adapter.addAll(newItems); } }; }
In the onCreate() method, we create a ListView, set an adapter to it AND set an OnScrollListener. The scrollListener's loadMore() method is called when the ListView is nearing its end and needs more data.
In loadMore(), an AsyncTask fetches more data and appends it to the ListView.
Here's the Magical OnScrollListener :
LazyLoader.java
import android.widget.AbsListView; public abstract class LazyLoader implements AbsListView.OnScrollListener { private boolean loading = true ; private int previousTotal = 0 ; private int threshold = 10; @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if(loading) { if(totalItemCount > previousTotal) { // the loading has finished loading = false ; previousTotal = totalItemCount ; } } // check if the List needs more data if(!loading && ((firstVisibleItem + visibleItemCount ) >= (totalItemCount - threshold))) { loading = true ; // List needs more data. Go fetch !! loadMore(view, firstVisibleItem, visibleItemCount, totalItemCount); } } // Called when the user is nearing the end of the ListView // and the ListView is ready to add more items. public abstract void loadMore(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount); }
The onScroll() method of the onScrollListener is called when the user scrolls the ListView.
In this method, we do calculations to check if the List is nearing its end. If yes, the loadMore() method is called. We have implemented the loadMore() method in the MainActivity, which will append the ListView with more data.
Here's the FetchItemsTask, if you're interested :
FetchItemsTask.java
import android.os.AsyncTask; import com.androidcocktail.lazyloader.utils.ResponseListener; import java.util.ArrayList; import java.util.List; public class FetchItemsTask extends AsyncTask<Void, Void, List<String>> { private int startIndex; private ResponseListener responseListener; public FetchItemsTask(int startIndex, ResponseListener listener) { this.startIndex = startIndex; this.responseListener = listener; } @Override protected List<String> doInBackground(Void... params) { try { //In this example, we are fetching dummy data locally; // but in a real world app its usually a network or database request which takes time. // So FAKE that time delay here. Thread.sleep(3000); } catch (InterruptedException e) { } // Fetch a maximum of 50 new items. int end = startIndex + 50 ; // Get the data. List<String> dummyItems = new ArrayList<>(); for(int i = startIndex ; i < end ; i++) { String item = "Item " + i ; dummyItems.add(item); } return dummyItems; } @Override protected void onPostExecute(List<String> newItems) { // give the new items back to the activity responseListener.onResponse(newItems); } }
The ResponseListener :
import java.util.List; public interface ResponseListener { public void onResponse(List<String> responseItems); }
I've broken some coding conventions for the sake of simplicity. You can find the proper, full source code at Github :) .