2016-01-08 36 views
0

我根据LruCache使用的示例编写了此适配器类。我遇到的问题如下:Android - 使用LruCache的图像GridView库 - 图像不断变化

如果我做了一个快速滑动,并且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

的问题是在你的BitmapWorkerTask onPostExecute()总是设置BitmapImageView并在GridView的意见被重用,所以你所看到的变化图像是当你滚动图像的更新和同ImageView是由于长卷轴而用于各种图像。

我的建议是添加的位置在ImageHolder并更新值上getView(),然后BitmapWorkerTask onPostExecute()您通过ImageHolder得到ImageView的当前位置,如果它是不一样的位置作为Bitmap你不需要由于图像已经滚出屏幕,因此需要更新它。

+0

工作就像一个魅力..谢谢你 – Anonymous