1

When I scroll back and forth through my GridView, my images aren't recycled correctly and will ultimately display the same image throughout the grid.

Recycling problem

Adapter

public class ImageAdapter extends BaseAdapter {
    private Context mContext;
    private List<String> mList;
    private int mheight;
    private int mwidth;
    private Bitmap nBitmap;

    public ImageAdapter(Context context, List<String> list, int height, int width) {
        mContext = context;
        mList = list;
        mheight = height;
        mwidth = width;
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        return mList.get(position).toString();
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imageView;
        if (convertView == null) {
            imageView = new ImageView(mContext);
            InputStream is;
            try {
                is = mContext.getAssets().open(mList.get(position));
                Bitmap bm = BitmapFactory.decodeStream(is);
                Bitmap mBitmap = Bitmap.createScaledBitmap(bm, mwidth / 3, mwidth / 3, false);
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

                this.nBitmap = mBitmap;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else {
            imageView = (ImageView) convertView;
        }
        imageView.setImageBitmap(nBitmap);
        return imageView;
    }
}

i tried to decode the bitmap off the Ui thread scrolling working fast but Thumbnails getting loaded 1 by 1 when starting the app and recycled thumbnails view get changed from orignal view and on low low memoery devices app crash while loading thumbnails from AsyncTask here is updated codde

public class ImageAdapter extends BaseAdapter {
private Context mContext;
private List<String> mList;
private int mheight;
private int mwidth;
private InputStream is;

public ImageAdapter(Context context, List<String> list, int height, int width) {
    mContext = context;
    mList = list;
    mheight = height;
    mwidth = width;
}


@Override
public int getCount() {
    return mList.size();
}

@Override
public Object getItem(int position) {
    return mList.get(position).toString();
}

@Override
public long getItemId(int position) {
    return 0;
}





@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    if (convertView == null) {
        imageView = new ImageView(mContext);
    } else {
        imageView = (ImageView) convertView;
    }


    InputStream is;
    try {
        is = mContext.getAssets().open(mList.get(position));
        Loadimage task = new Loadimage(imageView , mheight , mwidth);
        task.execute(is);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return imageView ;

}
 public class Loadimage extends AsyncTask<InputStream, Void, Bitmap>{
private final WeakReference<ImageView> imageViewReference;


private InputStream is = null;
private int width;


public Loadimage(ImageView imageView, int mheight, int mwidth) {
     imageViewReference = new WeakReference<ImageView>(imageView);
     this.width=mwidth;

    // TODO Auto-generated constructor stub
}

@Override
protected Bitmap doInBackground(InputStream... params) {
    is = params[0];

    if (is !=null) {

        Bitmap bitmap  = BitmapFactory.decodeStream(is);
        Bitmap nBitmap =Bitmap.createScaledBitmap(bitmap,width/3 , width/3, false);
        return nBitmap;     
    }
    return null; 
  }
 @Override
 protected void onPostExecute(Bitmap bitmap) {
    if (imageViewReference != null && bitmap != null) {
        final ImageView imageView = imageViewReference.get();
        if (imageView != null) {
            imageView.setImageBitmap(bitmap);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        }


}

}

Joseph27
  • 129
  • 3
  • 16

1 Answers1

3

You need to move the block where you generate the Bitmap outside of the if/then. Right now, you only generate the new Bitmap when convertView == null.

I believe your code would be correct as:

public class ImageAdapter extends BaseAdapter {
    private Context mContext;
    private List<String> mList;
    private int mheight;
    private int mwidth;

    public ImageAdapter(Context context, List<String> list, int height, int width) {
        mContext = context;
        mList = list;
        mheight = height;
        mwidth = width;
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        return mList.get(position).toString();
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imageView;
        if (convertView == null) {
            imageView = new ImageView(mContext);
        } else {
            imageView = (ImageView) convertView;
        }

        InputStream is;
        try {
            is = mContext.getAssets().open(mList.get(position));
            Bitmap bm = BitmapFactory.decodeStream(is);
            Bitmap bitmap = Bitmap.createScaledBitmap(bm, mwidth / 3, mwidth / 3, false);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

            imageView.setImageBitmap(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return imageView;
    }
}

Your scrolling will not be very fluid and you'll get lots of dropped frames because your Bitmap decoding code is inefficient (no caching), and it all happens on the UI thread, which is bad for responsiveness. The bottleneck in your current code is not the allocation and garbage-collection of the ImageViews.

The bottleneck is (probably by far) your handling and creation of Bitmaps.

You can take a look at the following links for advice:

Displaying Bitmaps Efficiently

And specifically this one:

Processing Bitmaps Off the UI Thread

yarian
  • 5,922
  • 3
  • 34
  • 48
  • i tried both of them and it's working as no recycling at all and scrolling is very laggy – Joseph27 Mar 22 '13 at 00:07
  • I am fairly sure that the problem is not because it is no longer recycling. I think your Bitmap generation is just slow. If you had a Bitmap cache and you loaded them in instead of decoding the stream and what not, it would be a lot faster. – yarian Mar 22 '13 at 00:37
  • i tried to decode the bitmap outside the ui thread the scrolling now so much faster but when i start the app thumbnails loading very slowly 1 by 1 and recycled views is not as original views i updated the code thanks in advance – Joseph27 Mar 23 '13 at 19:02
  • At this point, this is way outside the scope and topic of your original question. You should do research on your new issue, accept an answer if it helped you, and if after your research you still have trouble getting the views to do what you want, ask a new quesiton. – yarian Mar 25 '13 at 05:32
  • You should copy the last part of your question that you just added as a new one. – yarian Mar 25 '13 at 05:33