Android - 带有LruCache的图形GridView库 - 图像不断变化

时间:2016-01-08 16:16:19

标签: android android-gridview baseadapter android-lru-cache

我根据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; 
    }


}

1 个答案:

答案 0 :(得分:0)

问题在于BitmapWorkerTask onPostExecute()始终将Bitmap设置为ImageView,而GridView中的视图会被重复使用,因此您看到的更改图像是滚动时图像的更新,由于长滚动,同一ImageView被用于各种图像。

我的建议是在ImageHolder中添加一个位置并更新getView()上的值,然后在BitmapWorkerTask onPostExecute()上通过ImageView获取ImageHolder的当前位置{1}}如果它与Bitmap的位置不同,则您不需要更新它,因为图像已经滚出屏幕。