Question

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);
        }


}

}

Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top