Search code examples
androidandroid-listviewonscrolllistener

Load ListView data when user scrolls


Here is my code displaying a list that is being parsed from an html file.

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

    private ArrayList<String> descArray;

    @Override
    protected Void doInBackground(Void... arg0) {
        try {
            File file = new File(dir, getString(R.string.html_file));
            descArray = new ArrayList<String>();
            FileInputStream in = new FileInputStream(file);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    in, "UTF-8"));
            String line;
            while ((line = br.readLine()) != null) {
                Document doc = Jsoup.parse(line);
                Elements descs = doc.select("p");
                for (Element desc : descs) {
                    descArray.add(desc.text());
                }
            }
            in.close();
            br.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    @Override
    protected void onPostExecute(Void v) {
        MyAdapter mAdapter = new MyAdapter(getApplicationContext(),
            R.layout.list_layout, descArray);
        listView.setAdapter(mAdapter);
    }

There is a lot of data coming from this (over 100 items in the array) and it's taking a while to load. I was wondering if there is a way to load 10 items at a time and use an OnScrollListener to continue loading the data from the file? Any suggestions will be appreciated.


Solution

  • There appear to be many ways to accomplish running background code when you reach the end of a listview, the following snippet is what I chose to implement:

    lv.setOnScrollListener(new OnScrollListener() {
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            int threshold = 1;
            int count = lv.getCount();
            if (scrollState == SCROLL_STATE_IDLE) {
                if (lv.getLastVisiblePosition() >= count - threshold) {
                    items = (AddItems) new AddItems().execute(count);
                }
            }
        }
    });
    

    As for the class AddItem, what I wanted required creating a custom array object, Gift()

    public class Gift {
        private String descs;
        private String itemName;
        private String price;
        private String imageUrl;
    
        public Gift() {
        }
    
        public Gift(String p, String i, String d, String u) {
            this.descs = d;
            this.itemName = i;
            this.price = p;
            this.imageUrl = u;
        }
    
        public String getDetails() {
            return descs;
        }
    
        public void setDetails(String details) {
            this.descs = details;
        }
    } // You get the idea
    

    Then I would have to iterate through the file, adding desired strings to their respect ArrayList, and combine all three lists into an ArrayList<Gift> which is shown below.

    private class AddItems extends AsyncTask<Integer, Void, ArrayList<Gift>> {
    
        @Override
        protected ArrayList<Gift> doInBackground(Integer... integer) {
            try {
                amountArray = new ArrayList<String>();
                itemArray = new ArrayList<String>();
                descArray = new ArrayList<String>();
                imageUrls = new ArrayList<String>();
                finalArray = new ArrayList<Gift>();
                File file = new File(Ids.dir, getString(R.string.html_file));
                FileInputStream in = new FileInputStream(file);
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        in, "UTF-8"));
                String line;
                int itemNumber = 0;
                while ((line = br.readLine()) != null) {
                    Document doc = Jsoup.parse(line);
                    Elements titles = doc.select("h4[class=title]");
                    Elements amounts = doc.select("div[class=price]");
                    Elements descs = doc.select("p");
                    Elements urls = doc.select("img[class=gallery-image]");
                    for (Element price : amounts) {
                        itemNumber++;
                        amountArray.add(price.text());
                    }
                    for (Element title : titles) {
                        itemArray.add(title.text());
                    }
                    for (Element desc : descs) {
                        descArray.add(desc.text());
                    }
                    for (Element url : urls) {
                        imageUrls.add(url.attr("src"));
                    }
    
                    // totalShowing is a final integer with a value of 10
                    // which only iterates through 10 objects plus 
                    // integer[0], which is the total number of items 
                    // shown in the listview.
                    if (itemNumber == totalShowing + integer[0] + 1) {
                        break;
                    }
                }
                in.close();
                br.close();
                finalArray = new ArrayList<Gift>();
    
                //  Only add to finalArray the items after position integer[0]
                //  so we don't add items we've already added
                for (int i = integer[0]; i < amountArray.size(); i++) {
                    finalArray.add(new Gift(amountArray.get(i), itemArray
                            .get(i), descArray.get(i), imageUrls.get(i)));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return finalArray;
        }
    
        @Override
        protected void onPostExecute(ArrayList<Gift> result) {
            super.onPostExecute(result);
            da.addItems(result);
        }
    }
    

    After that, all I had to do was change my adapter to extend ArrayList<Gift> and add the following code:

    public void addItems(ArrayList<Gift> newItems) {
        if (null == newItems || newItems.size() <= 0) {
            return;
        }
        if (null == finalArray) {
            finalArray = new ArrayList<Gift>();
        }
        finalArray.addAll(newItems);
        notifyDataSetChanged();
    }