5

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();
            }
        }
KC Chai
  • 1,607
  • 9
  • 30
  • 59
  • My code is not functioning as intended. It just loads all my gridview items, then when i scroll to the bottom it just refreshes. Anyone can help me? – KC Chai Aug 29 '12 at 12:04

1 Answers1

5

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.

Community
  • 1
  • 1
Michel-F. Portzert
  • 1,785
  • 13
  • 16
  • Thanks Michel. But, I'm already using a lazylist imageloader. The reason I ask this question is because I want learn more about onScrollListener. :) – KC Chai Aug 29 '12 at 05:17
  • 1
    Oh sorry, I see then, your question is more about making some sort of paging for the xml downloading part, using onScrollListener. I'll edit my answer soon. – Michel-F. Portzert Aug 29 '12 at 05:55
  • Michel, Could you please guide me on this? – KC Chai Aug 30 '12 at 01:48
  • I've got this idea. Can I limit my xml to 20 items for the first time load . Then onscroll to the bottom, download another 20 items from xml. Repeat until xml is empty. – KC Chai Aug 30 '12 at 05:25
  • Yes, this is the idea. However, if you still need help about the paging itself, I'm writing some code to show the mechanism, because the task you call at each loading doesn't add 20 items but reload the entire gridview.. – Michel-F. Portzert Aug 30 '12 at 05:28
  • Currently my onscrolllistener logic is obviously wrong. The example from http://benjii.me/2010/08/endless-scrolling-listview-in-android/ doesnt use xmlparser. So I think it not right using it on my codes. – KC Chai Aug 30 '12 at 05:31
  • The example is not about xml parsing, it's about paging using onScrollListener. What you want to do is add 20 items every time you reach the bottom of you scroll, right ? The only part you have to do on your own is this asyncTask that will download and parse 20 more items and add them to your adapter. – Michel-F. Portzert Aug 30 '12 at 05:43
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/16003/discussion-between-droid-beginner-and-michel-f-portzert) – KC Chai Aug 30 '12 at 05:47
  • Wiki removed. Thanks for all the effort you put into this. – Tim Post Aug 30 '12 at 13:02
  • hi Michel-F. Portzert --- i did same thing you said here ..... i make a network call in Async Task and i get callback for response ........ in call back i add data to adapter and call notifyDataSetChanged(). My gridview gets updated but it shows from 1st Element. it is not able to keep state of gridview.........can u tell why this could be? I am having Custome adapter – ANUP May 23 '13 at 00:24