私は、多くの画像を含む 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);
}