Question

Here is my BitmapWorkerTask to load image to a ViewPager. I'm trying to add a Horizontal ProgressBar to each page for better UX showing the progress of image's loading. (I've already been using a 'indeterminate' circle progress bar.)

Is the BitmapWorkerTask even the right place for adding the progress bar, and if so how to do it?

/**
 * The actual AsyncTask that will asynchronously process the image.
 */
private class BitmapWorkerTask extends AsyncTask<Object, Void, Bitmap> {
    private Object data;
    private final WeakReference<ImageView> imageViewReference;

    public BitmapWorkerTask(ImageView imageView) {
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    /**
     * Background processing.
     */
    @Override
    protected Bitmap doInBackground(Object... params) {            

        data = params[0];
        final String dataString = String.valueOf(data);
        Bitmap bitmap = null;

        // Wait here if work is paused and the task is not cancelled
        synchronized (mPauseWorkLock) {
            while (mPauseWork && !isCancelled()) {
                try {
                    mPauseWorkLock.wait();
                } catch (InterruptedException e) {}
            }
        }

        // If the image cache is available and this task has not been cancelled by another
        // thread and the ImageView that was originally bound to this task is still bound back
        // to this task and our "exit early" flag is not set then try and fetch the bitmap from
        // the cache
        if (mImageCache != null && !isCancelled() && getAttachedImageView() != null
                && !mExitTasksEarly) {
            bitmap = mImageCache.getBitmapFromDiskCache(dataString);
        }

        // If the bitmap was not found in the cache and this task has not been cancelled by
        // another thread and the ImageView that was originally bound to this task is still
        // bound back to this task and our "exit early" flag is not set, then call the main
        // process method (as implemented by a subclass)
        if (bitmap == null && !isCancelled() && getAttachedImageView() != null
                && !mExitTasksEarly) {
            bitmap = processBitmap(params[0]);
        }

        // If the bitmap was processed and the image cache is available, then add the processed
        // bitmap to the cache for future use. Note we don't check if the task was cancelled
        // here, if it was, and the thread is still running, we may as well add the processed
        // bitmap to our cache as it might be used again in the future
        if (bitmap != null && mImageCache != null) {
            mImageCache.addBitmapToCache(dataString, bitmap);
        }            

        return bitmap;
    }

    /**
     * Once the image is processed, associates it to the imageView
     */
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        // if cancel was called on this task or the "exit early" flag is set then we're done
        if (isCancelled() || mExitTasksEarly) {
            bitmap = null;
        }

        final ImageView imageView = getAttachedImageView();
        if (bitmap != null && imageView != null) {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "onPostExecute - setting bitmap");
            }
            setImageBitmap(imageView, bitmap);
        }
    }

    @Override
    protected void onCancelled(Bitmap bitmap) {
        super.onCancelled(bitmap);
        synchronized (mPauseWorkLock) {
            mPauseWorkLock.notifyAll();
        }
    }

    /**
     * Returns the ImageView associated with this task as long as the ImageView's task still
     * points to this task as well. Returns null otherwise.
     */
    private ImageView getAttachedImageView() {
        final ImageView imageView = imageViewReference.get();
        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

        if (this == bitmapWorkerTask) {
            return imageView;
        }

        return null;
    }
}
Was it helpful?

Solution 2

Well, just spent 4 hours and did the 'impossible', the trick is:

  1. Measuring the progress when loading the image from HTTP URL before it gets passed to the BitmapWorkerTask. This link is a great tutorial for that.
  2. Pass the progress update from the loading URL method to the BitmapWorkerTask class, however the publishProgress() method only works within the AsyncTask so to work around that follow this.
  3. And a whole lots of troubleshooting, trial and error to customize specifically to your needs.

Good luck! Hope this helps people out there get started on the right direction.

OTHER TIPS

considering how you're loading your Bitmap

return BitmapFactory.decodeStream(params[0].openConnection().getInputStream());

it will be impossible to give an actual percentual progress. For an undefined progressBar you can pass on the constructor the progressbar and save it in another WeakReference and do like this on your code:

// Before start hide the ImageView and show the progressBar
@Override
protected void onPreExecute(){
    // do the weak reference stuff and call
    progressBar.setVisibility(View.VISIBLE);
    imageView.setVisibility(View.INVISIBLE);
}

// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
     // do the weak refence stuff and call
    progressBar.setVisibility(View.INVISIBLE);
    imageView.setVisibility(View.VISIBLE);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top