Android Using GridView with OnScrollListener

KC Chai picture KC Chai · Aug 29, 2012 · Viewed 17.2k times · Source

I'm building a gridview that contains alot of images likely around 1000++ pictures. To reduce the loading time for the gridview, I want to implement an onScrollListener using AbsListView. I will limit 20 images per view, then when scrolling reaches bottom it will load another 20 images. This will repeat until all images has been loaded.

I've been googling samples, but doesnt seem to find one that suits my codes. Could anyone please guide me how it is done? I'm currently using imageloader Lazylist for my images. Also I'm using AsyncTask.

MainGridView.class

    public class MainGridView extends SherlockActivity {

    private ProgressDialog pDialog;
    ArrayList<HashMap<String, String>> songsList;
    static final String KEY_SONG = "song"; 
    static final String KEY_ID = "id";
    static final String KEY_TITLE = "title";
    static final String KEY_ARTIST = "artist";
    static final String KEY_CAT_ARTIST = "artistcat";
    static final String KEY_DURATION = "duration";
    static final String KEY_THUMB_URL = "thumb_url";
    static final String KEY_BIG_URL = "big_url";
    static final String KEY_CAT_URL = "cat_url";
    static String IMAGE_POSITION;
    GridView grid;
    MainGridViewLazyAdapter adapter;
    String cat_url;
    String artist_url;
    private int visibleThreshold = 5;
    private int currentPage = 0;
    private int previousTotal = 0;
    private boolean loading = true;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gridview_main);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        checkInternetConnection();

        grid = (GridView) findViewById(R.id.grid_view);




    grid.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        // TODO Auto-generated method stub
        if (loading) {
            if (visibleItemCount > totalItemCount) {
                loading = false;
                previousTotal = totalItemCount;
                currentPage++;
            }
        }
        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
            // I load the next page of gigs using a background task,
            // but you can call any function here.
            new loadGridView().execute(currentPage + 1);
            loading = true;
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub

    }
    });


}

    public class loadGridView extends AsyncTask<Integer, String, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(MainGridView.this);
            pDialog.setTitle("Connect to Server");
            pDialog.setMessage("This process can take a few seconds to a few minutes, depending on your Internet Connection Speed.");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(false);
            pDialog.show();
        }
        @Override
        protected String doInBackground(Integer... args) {
            // updating UI from Background Thread
                    Intent in = getIntent();
                    songsList = new ArrayList<HashMap<String, String>>();
                    cat_url = in.getStringExtra(KEY_CAT_URL);
                    artist_url = in.getStringExtra(KEY_CAT_ARTIST);


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

                    NodeList nl = doc.getElementsByTagName(KEY_SONG);
                    // looping through all song nodes <song>
                    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_TITLE, parser.getValue(e, KEY_TITLE));
                        map.put(KEY_ARTIST, parser.getValue(e, KEY_ARTIST));
                        map.put(KEY_DURATION, parser.getValue(e, KEY_DURATION));
                        map.put(KEY_THUMB_URL, parser.getValue(e, KEY_THUMB_URL));
                        map.put(KEY_BIG_URL, parser.getValue(e, KEY_BIG_URL));
                        // adding HashList to ArrayList
                        songsList.add(map);

                    }
                    return null;
                }   


        @Override
        protected void onPostExecute(String args) {
            ActionBar   ab = getSupportActionBar();
                        ab.setTitle(artist_url);

            adapter=new MainGridViewLazyAdapter(MainGridView.this, songsList);   
            grid.setAdapter(adapter);
            pDialog.dismiss();
            }
        }

Answer

Michel-F. Portzert picture Michel-F. Portzert · Aug 29, 2012

I suppose you want to load images from Urls. For that purpose, you could use this solution: Lazy load of images in ListView

In order to control your paging using onScrollListener, I think you want to see the Endless scrolling example. This is a simplistic example, but the only thing you have to add is a check if you have reached the last item of your xml.

Inside your AsyncTask (called at each new loading), you would only parse a bit of data from your xml (corresponding to 20 items in your case). This is an example of use based on your code:

public class MainGridView extends SherlockActivity implements OnScrollListener {

    public static final String KEY_SONG = "song"; 
    public static final String KEY_ID = "id";
    public static final String KEY_TITLE = "title";
    public static final String KEY_ARTIST = "artist";
    public static final String KEY_CAT_ARTIST = "artistcat";
    public static final String KEY_DURATION = "duration";
    public static final String KEY_THUMB_URL = "thumb_url";
    public static final String KEY_BIG_URL = "big_url";
    public static final String KEY_CAT_URL = "cat_url";

    private final static int ITEMS_PPAGE = 20;

    private ProgressDialog mDialog;
    private ArrayList<HashMap<String, String>> mSongsList;

    private static String IMAGE_POSITION;
    private GridView mGridView;
    //MainGridViewLazyAdapter mAdapter;
    private ArrayAdapter<String> mAdapter;
    private String cat_url;
    private String artist_url;

    private int mVisibleThreshold = 5;
    private int mCurrentPage = 0;
    private int mPreviousTotal = 0;
    private boolean mLoading = true;
    private boolean mLastPage = false;

    private String mXml;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        setTheme(SherlockBarUtils.getCurrentTheme(this));
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gridview_main);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        //checkInternetConnection();

        mGridView = (GridView) findViewById(R.id.grid_view);
        mGridView.setOnScrollListener(this);

        mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
        //mAdapter=new MainGridViewLazyAdapter(MainGridView.this);  
        mGridView.setAdapter(mAdapter);

        new DownloadDataAsyncTask().execute();
    }

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

        if (mLoading) {
            if (totalItemCount > mPreviousTotal) {

                mLoading = false;
                mPreviousTotal = totalItemCount;
                mCurrentPage++;

                // Find your own condition in order to know when you 
                // have finished displaying all items
                if (mCurrentPage + 1 > 50) {
                    mLastPage = true;
                }
            }
        }
        if (!mLastPage && !mLoading && 
                (totalItemCount - visibleItemCount) <= (firstVisibleItem + mVisibleThreshold)) {
            new AddItemsAsyncTask().execute();
            mLoading = true;
        }
    }

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

    }

    public class DownloadDataAsyncTask extends AsyncTask<String, String, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mDialog = new ProgressDialog(MainGridView.this);
            mDialog.setTitle("Connect to Server");
            mDialog.setMessage("This process can take a few seconds to a few minutes, depending on your Internet Connection Speed.");
            mDialog.setIndeterminate(false);
            mDialog.setCancelable(false);
            mDialog.show();
        }
        @Override
        protected String doInBackground(String... args) {

            // Downloading XML

            /*
            Intent in = getIntent();
            mSongsList = new ArrayList<HashMap<String, String>>();
            cat_url = in.getStringExtra(KEY_CAT_URL);
            artist_url = in.getStringExtra(KEY_CAT_ARTIST);

            XMLParser parser = new XMLParser();
            mXml = parser.getXmlFromUrl(cat_url); // getting XML from URL
            */

            return null;
        }   

        @Override
        protected void onPostExecute(String args) {

            /*
            getSupportActionBar().setTitle(artist_url);
            */
            mDialog.dismiss();
            mLoading = false;
        }
    }

    public class AddItemsAsyncTask extends AsyncTask<Integer, String, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        @Override
        protected String doInBackground(Integer... args) {

            MainGridView.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {

                    // Parsing 20 more items and adding them to the adapter
                    for (int i = mCurrentPage * ITEMS_PPAGE; i < (mCurrentPage + 1) * ITEMS_PPAGE; i++) {
                        MainGridView.this.mAdapter.add(String.valueOf(Math.random() * 5000));
                    }
                    MainGridView.this.mAdapter.notifyDataSetChanged();
                }
            });
            return null;
        }

        @Override
        protected void onPostExecute(String args) {

        }
    }
}

For the convenience, I used texts instead of images inside the GridView. I focused on the paging system so I didn't parse XML, just added some random values on the fly.

Also, you could consider using the same addItemsAsyncTask to download only a part (20 items) of your xml at each loading instead of downloading the whole 1000+ items before creating the GridView.