5

I have this code of a custom grid view and each time I try to run it, it crashes caused by an OutOfMemoryException. I guess the solution is to resize the images in the array ...

main activity code :

public class AndroidGridLayoutActivity extends Activity {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.grid_layout);

            GridView gridView = (GridView) findViewById(R.id.grid_view);

            // Instance of ImageAdapter Class
            gridView.setAdapter(new ImageAdapter(this));

            /**
             * On Click event for Single Gridview Item
             * */
            gridView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View v,
                        int position, long id) {

                    // Sending image id to FullScreenActivity
                    Intent i = new Intent(getApplicationContext(), FullImageActivity.class);
                    // passing array index
                    i.putExtra("id", position);
                    startActivity(i);
                }
            });
        }



}

image adapter code :

public class ImageAdapter extends BaseAdapter {
    private Context mContext;

    // Keep all Images in array
    public Integer[] mThumbIds = {
            R.drawable.pic_1, R.drawable.pic_2,
            R.drawable.pic_3, R.drawable.pic_4,
            R.drawable.pic_5, R.drawable.pic_6,
            R.drawable.pic_7, R.drawable.pic_8,
            R.drawable.pic_9, R.drawable.pic_10,
            R.drawable.pic_11, R.drawable.pic_12,
            R.drawable.pic_13, R.drawable.pic_14,
            R.drawable.pic_15
    };

    // Constructor
    public ImageAdapter(Context c){
        mContext = c;
    }

    @Override
    public int getCount() {
        return mThumbIds.length;
    }

    @Override
    public Object getItem(int position) {
        return mThumbIds[position];
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {         
        ImageView imageView = new ImageView(mContext);
        imageView.setImageResource(mThumbIds[position]);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setLayoutParams(new GridView.LayoutParams(70, 70));

        return imageView;
    }
}

full screen code :

public class FullImageActivity extends Activity {


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.full_image);

        // get intent data
        Intent i = getIntent();

        // Selected image id
        int position = i.getExtras().getInt("id");
        ImageAdapter imageAdapter = new ImageAdapter(this);

        ImageView imageView = (ImageView) findViewById(R.id.full_image_view);
        imageView.setImageResource(imageAdapter.mThumbIds[position]);
    }

}

any advice please??

6
  • 3
    How big are the images? Commented Feb 26, 2014 at 13:45
  • how big is one of these? R.drawable.pic_1 Commented Feb 26, 2014 at 13:45
  • 268,233 bytes for each Commented Feb 26, 2014 at 13:47
  • 1
    @SereenShalby It's the dimensions that are relevant, not the size of the file. Android reads the images into a byte array, such that each pixel is stored as four bytes. That translates to width × height × 4. Commented Feb 26, 2014 at 13:52
  • @PaulLammertsma how can i fix this please? Commented Feb 26, 2014 at 13:54

2 Answers 2

2

You are attempting to allocate too much memory for image data. As you explained in the comments, your images are fairly large and they are being read as soon as the adapter is created.

Reading this into memory will consume 4 bytes per pixel, so if your images are 1024 pixels square, the math is:

  • 1024 × 1024 × 4 = 4MB
  • 15 images × 4 MB/image = 60MB

This likely exceeds the heap budget of 48MB.

You will likely want to improve the efficiency through which you display these images. Consider:

  1. Only loading the image when it is shown, using GridView's mechanisms for getView();
  2. Loading bitmaps with a sample size using BitmapFactory.
Sign up to request clarification or add additional context in comments.

2 Comments

please can you explain more??
Upon further review, it appears that you're already (partly) using the getView() mechanism. I would urge you to correctly recycle your views by using convertView when available, instead of creating a new view each time. Your problem should be entirely circumvented by loading scaled down bitmaps. You may want to consider using an existing library such as Picasso.
1

Esp for "..loading the images in a GridView:
you can use inSampleSize to load all images and replace the visible images by the original ones- meaning for the view part that are visible, dynamically load images without the inSampleSize for the BitmapFactory and its Options.

You could scale them down depending on different devices to load the images without facing a memory problem. In your case, some phones may not exhibit the same behavior on the first run, but eventually, without handling an optimized image loading solution, app will crash.

Topic under Load a Scaled Down Version into Memory.
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Out of memory error on Android

On how to avoid them:
How to avoid an out of memory error while using bitmaps in Android

For an overview:
http://blogs.innovationm.com/android-out-of-memory-error-causes-solution-and-best-practices/ http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html

Before setting a drawable as the background for your imageview, i.e.:

iv.setBackgroundResource(R.drawable.image);  

Get a scaled bitmap or try other options like inSampleSize, do check how your solution affects the quality of your image too.

For the comment:

Bitmap drawableImage=BitmapFactory.decodeResource(context.getResources(),R.drawable.image);
Bitmap bitmap = Bitmap.createScaledBitmap(drawableImage, width, height, false);
Drawable drawableScaled = new BitmapDrawable(context.getResources(), bitmap);

3 Comments

how can i do this for an integer array of images ??
@SereenShalby the edit in answer
R.drawable.image is your imageAdapter.mThumbIds[position]

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.