Search code examples
androidandroid-listviewandroid-progressbarandroid-download-manager

How to update progressbar in a ListView item


I have a ListView attached to an ArrayAdapter. When the user clicks a download button for an item in the ListView a download starts using the DownloadManager.

What I want to do is to track the download progress with a progress bar (placed in the item layout). How can this be achieved?

The way Pocket Cast does it is exacly what I'm after:

Pocket Cast exampel http://www.mrcrab.net/images/thumb_big/9982-Pocket_Casts_Apk_v4.3.2_Android-0.jpg

Note: I know how to work with the DownloadManager, it's the instant update of the progress bar that is tricky.


Solution

  • This is the way I finally solved it (after many iterations and different implementations). It's a bit tricky but basically you need three things:

    1. An AsyncTask that gathers meta data
    2. A scroll listener that tells us when the user has stopped scrolling/flinging
    3. A clever algorithm that finds any visible row that needs updating and asks the adapter to only update that specific row

    This is the way I designed and implemented it:

    Screenshot

    I wrote in more detail about it here, and please see the github code for the complete imlementation.

        private class UpdaterAsyncTask extends AsyncTask<Void, Void, Void> {
    
        boolean isRunning = true;
    
        public void stop() {
            isRunning = false;
        }
    
        @Override
        protected Void doInBackground(Void... params) {
    
            while (isRunning) {
    
                // Gather data about your adapter objects
                // If an object has changed, mark it as dirty                
    
                publishProgress();
    
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            return null;
        }
    
        @Override
        protected void onProgressUpdate(Void... params) {
            super.onProgressUpdate();
    
            // Update only when we're not scrolling, and only for visible views
            if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) {
                int start = mListview.getFirstVisiblePosition();
                for(int i = start, j = mListview.getLastVisiblePosition(); i<=j; i++) {
                    View view = mListview.getChildAt(i-start);
                    if (((Content)mListview.getItemAtPosition(i)).dirty) {
                        mListview.getAdapter().getView(i, view, mListview); // Tell the adapter to update this view
                    }
    
                }
            }
    
          }
        }