ListView的多线程使得错误的项目/根本没有项目出现

时间:2013-09-12 07:38:26

标签: android multithreading listview concurrency android-asynctask

我正在开发一个应用程序,其中我有一个带有大量图像的ListView。为了确保顺畅的用户体验,我从Android开发人员那里学到了这一课:http://developer.android.com/training/displaying-bitmaps/process-bitmap.html。我完全按照那里描述的那样实现了并发处理程序(据我所知),但它并不能很好地工作。当用户简单地浏览ListView时它做了一个合理的工作,但是当用户甩动ListView并突然停止它时,出现错误的图像或者有时没有图像出现。我在后台加载图片的代码是:

public class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

private final WeakReference<ImageView> mImageViewReference;
private int mData = 0;


public BitmapWorkerTask(ImageView imageView) {
    // Use a WeakReference to ensure the ImageView can be garbage collected
    mImageViewReference = new WeakReference<ImageView>(imageView);
}

// Decode image in background
@Override
protected Bitmap doInBackground(Integer... params) {
    Bitmap bitmap = null;

    mData = params[0];

    ...

    if (mLruCache.getBitmapFromMemoryCache(key) != null) {
        bitmap = mLruCache.getBitmapFromMemoryCache(key);
    } else {
        bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().toString() + "/MyApp/" + key + ".png", options);
        mLruCache.addBitmapToMemoryCache(key, bitmap);
    }

    return bitmap;
}

// Once complete, see if ImageView is still around and set bitmap
@Override
protected void onPostExecute(Bitmap bitmap) {
    if (isCancelled()) bitmap = null;

    if (mImageViewReference != null && bitmap != null) {
        final ImageView imageView = mImageViewReference.get();

        if (imageView != null) {
            imageView.setImageBitmap(bitmap);
        }
    }
}

public static class AsyncDrawable extends BitmapDrawable {
    private static WeakReference<BitmapWorkerTask> mBitmapWorkerTaskReference;

    public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        mBitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
    }

    public BitmapWorkerTask getBitmapWorkerTask() {
        return mBitmapWorkerTaskReference.get();
    }
}

public static boolean cancelPotentialWork(int data, ImageView imageView) {
    BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

    if (bitmapWorkerTask != null) {
        int bitmapData = bitmapWorkerTask.mData;
        if (bitmapData != data) {
            // Cancel previous task
            bitmapWorkerTask.cancel(true);
        } else {
            return false;
        }
    }
    return true;
}

public static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
       if (imageView != null) {
           final Drawable drawable = imageView.getDrawable();
           if (drawable instanceof AsyncDrawable) {
               AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
               return asyncDrawable.getBitmapWorkerTask();
           }
        }
        return null;
    }
}

在我的适配器的getView()方法中,我有:

// Load images in the background
int data = position;
if (BitmapWorkerTask.cancelPotentialWork(data, imageView)) {
    BitmapWorkerTask bitmapWorkerTask = new BitmapWorkerTask(imageView);
    BitmapWorkerTask.AsyncDrawable asyncDrawable = new BitmapWorkerTask.AsyncDrawable(mContext.getResources(), null, bitmapWorkerTask);
    imageView.setImageDrawable(asyncDrawable);
    bitmapWorkerTask.execute(params);
}

1 个答案:

答案 0 :(得分:3)

总是很难做到正确...为什么不用UniversalImageLoader