我根据LruCache用法的例子编写了这个适配器类。我遇到的问题如下:
如果我快速滑动并且GridView向下或向上滚动,(位图尚未缓存),图像将使用错误的位图绘制而不是保持为空。当GridView仍然(不滚动)时,图像不断变化,直到最后加载正确的图像然后一切都应该是它应该是。我看不出我的代码有什么问题...有关如何避免这种情况的任何想法?
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;
}
}
答案 0 :(得分:0)
问题在于BitmapWorkerTask onPostExecute()
始终将Bitmap
设置为ImageView
,而GridView
中的视图会被重复使用,因此您看到的更改图像是滚动时图像的更新,由于长滚动,同一ImageView
被用于各种图像。
我的建议是在ImageHolder
中添加一个位置并更新getView()
上的值,然后在BitmapWorkerTask onPostExecute()
上通过ImageView
获取ImageHolder
的当前位置{1}}如果它与Bitmap
的位置不同,则您不需要更新它,因为图像已经滚出屏幕。