androidperformancegalleryview

Android GalleryView Recycling


I'm using GalleryView with ~40 images, and so slow because no recycling...

Anyone can show me a basic recycling to GalleryView on getView method.

public class ImageAdapter extends BaseAdapter {
    int mGalleryItemBackground;
    private Context mContext;

    private Integer[] mImageIds = {
            R.drawable.sample_1,
            R.drawable.sample_2,
            R.drawable.sample_3,
            R.drawable.sample_4,
            R.drawable.sample_5,
            R.drawable.sample_6,
            R.drawable.sample_7
    };

    public ImageAdapter(Context c) {
        mContext = c;

        TypedArray a = c.obtainStyledAttributes(R.styleable.HelloGallery);
        mGalleryItemBackground = a.getResourceId(
                R.styleable.HelloGallery_android_galleryItemBackground, 0);
        a.recycle();
    }

    public int getCount() {
        return mImageIds.length;
    }

     public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView i = new ImageView(mContext);

        i.setImageResource(mImageIds[position]);
        i.setLayoutParams(new Gallery.LayoutParams(150, 100));
        i.setScaleType(ImageView.ScaleType.FIT_XY);
        i.setBackgroundResource(mGalleryItemBackground);

        return i;
    }
}

Solution

  • Instead of creating a new ImageView in getView you should convert the convertView to the view you want. Here is an example of one way to do it:

    public View getView(int position, View cv, ViewGroup parent) {
    
        if (! convertView istanceof ImageView)
        {
            ImageView cv = new ImageView(mContext);
            cv.setLayoutParams(new Gallery.LayoutParams(150, 100));
            cv.setScaleType(ImageView.ScaleType.FIT_XY);
            cv.setBackgroundResource(mGalleryItemBackground);
    
        }
        cv.setImageResource(mImageIds[position]);
    
        return cv;
    }
    

    Simply convert the convertView to match what you want, but first make sure its the proper view type.

    Update: You should also downsample the images before you display them. Lets assume that you have a 500x500 pixel image saved under res/drawable but the image is only going to take up 125x125 pixels on the screen. You need to downsample the image before you display it. To know how much you need to downsample the bitmap you must first get its size

    int maxSize = 125; // make 125 the upper limit on the bitmap size
    int resId; // points to bitmap in res/drawable
    
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true; // Only get the bitmap size, not the bitmap itself
    BitmapFactory.decodeResource(c.getResources(), resId, opts);
    
    int w = opts.outHeight, h = opts.outHeight;
    int maxDim = (w>h)?w:h; // Get the bigger dimension
    

    Now that we have the size calculate how much to downsample the image. If we have a 500x500 bitmap and we want a 125x125 bitmap we keep 1 out of every 4 pixels which we get from int inSample = 500/125;

    int inSample = maxDim/maxSize; 
    
    opts = new BitmapFactory.Options();
    opts.inSampleSize = inSample;
    

    Now simply decode the resources and we have our down-sampled bitmap.

    Bitmap b = BitmapFactory.decodeResource(c.getResources(), resId, opts);
    

    Keep in mind that the original bitmap is unaffected. You can decode the image again and set opts.inSampleSize to 1 and you will get the entire 500x500 bitmap image.