I wrote this adapter class based on examples of LruCache usage. The problem I encountered is the following:
If I do a fast swipe and the GridView scrolls really far down or up, (where the bitmaps are not yet cached) the images are drawn with the wrong bitmaps instead of staying empty. The images keep changing while the GridView is still (not scrolling), until finaly the correct ones are loaded and then then everything is as it should be. I cant see anything wrong with my code...Any thoughts on how to avoid this?
public class ImageGalleryAdapter extends BaseAdapter {
@SuppressLint("NewApi")
private MyLruCache mMemoryCache;
int size;
BaseAdapter adapter;
LayoutInflater mInflater;
ArrayList<ImageItem> photos;
Context con;
ContentResolver cr;
@SuppressLint("NewApi")
public ImageGalleryAdapter(ArrayList<ImageItem> photoList,Context con, int size, GridView gridView) {
this.photos=photoList;
this.size=size;
this.con=con;
adapter=this;
mInflater = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
cr = con.getContentResolver();
final int memClass = ((ActivityManager)con.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 4;
mMemoryCache = new MyLruCache(cacheSize) {
@SuppressLint("NewApi")
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
};
}
public int getCount() { return photos.size(); }
public Object getItem(int position) { return photos.get(position); }
public long getItemId(int position) { return position; }
@SuppressLint("InflateParams")
public View getView( final int position, View convertView, ViewGroup parent) {
ImageHolder holder;
if (convertView == null) {
holder = new ImageHolder();
convertView = mInflater.inflate(R.layout.image_gallery_item, null);
holder.imageview = (ImageView) convertView.findViewById(R.id.thumbImage);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.itemCheckBox);
convertView.setTag(holder);
} else { holder = (ImageHolder) convertView.getTag(); }
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams)holder.imageview.getLayoutParams();
params.width=size; params.height=size;
holder.imageview.setLayoutParams(params);
final Bitmap bm = mMemoryCache.getBitmapFromCache(photos.get(position).filename);
if (bm == null){
mMemoryCache.getNewBitmap(holder.imageview, position);
}
if(bm!=null && !bm.isRecycled()){
holder.imageview.setImageBitmap(bm);
holder.imageview.setScaleType(ScaleType.FIT_XY);
}
else{
holder.imageview.setImageResource(R.drawable.loading);
}
return convertView;
}
class ImageHolder {
ImageView imageview;
CheckBox checkbox;
}
class MyLruCache extends LruCache<String, Bitmap>{
public MyLruCache(int maxSize) {
super(maxSize);
}
@SuppressLint("NewApi")
public void addBitmapToCache(String key, Bitmap bitmap) {
if (getBitmapFromCache(key) == null) {
put(key, bitmap);
}
}
@SuppressLint("NewApi")
public Bitmap getBitmapFromCache(String key) {
return (Bitmap) get(key);
}
public void getNewBitmap(ImageView imageview, int position) {
BitmapWorkerTask task = new BitmapWorkerTask(imageview);
task.execute(photos.get(position));
}
class BitmapWorkerTask extends AsyncTask<ImageItem, Void, Bitmap>{
private final WeakReference<ImageView> imageViewReference;
ImageItem item;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected Bitmap doInBackground(ImageItem... params) {
ImageItem item = params[0];
this.item=item;
String filename = item.filename;
final Bitmap bitmap = getBitmapForImageItem(item);
mMemoryCache.addBitmapToCache(String.valueOf(filename), bitmap);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView)imageViewReference.get();
if (imageView != null) {
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setImageBitmap(bitmap);
}
}
}
}
}
public Bitmap getBitmapForImageItem(ImageItem item){
long imageID=item.imageId;
Bitmap bm = null;
if(!item.isVideo){
bm=MediaStore.Images.Thumbnails.getThumbnail( cr, imageID, MediaStore.Images.Thumbnails.MICRO_KIND, null);
}
else{
bm=MediaStore.Video.Thumbnails.getThumbnail( cr, imageID, MediaStore.Video.Thumbnails.MICRO_KIND, null);
}
if(bm==null){
try{
Bitmap newbitmap=F.bitmapInScreenSizeFromPath(item.filename, con, 70, 70);
bm=F.cropAndScaleBitmap(newbitmap, 70, 70);
newbitmap.recycle();
}catch(Exception e){}
}
return bm;
}
}