Search code examples
androidimageviewandroid-memory

Android allocates 9x memory for each ImageView as required by default


While adding a ViewPager and running into some OutOfMemory errors, I realized that my default method of ImageView.setImageResource(resId) was causing 9x more RAM to be allocated than need be. In my example, I had a 1920 x 1080 image which at native resolution was slightly bigger than the ImageView object it was placed in. I could expect some downsizing of the image but would not expect more than 12.6 MB to be allocated (1920 x 1080 x 4 bytes). However, 74.6 MB was allocated per image, and with 4 images loaded this quickly blew the VM memory budget away.

To solve this, I changed the method to the slightly longer code below - now each image is allocated exactly the native amount of memory expected (12.6 MB), and the images still load quickly and look great.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inSampleSize = 1;
Bitmap bm = BitmapFactory.decodeResource(getResources(), resId, options);
mImageView.setImageBitmap(bm);

For reference, my device is a Nexus 5 with 1920 x 1080, xxhdpi, 3x scaling factor (dp to pixels). I imagine that internally the OS is scaling the image up 3x3 (=9x) to match the scaling factor, but that does not make sense since the original image is at native resolution of the full screen size.

What is the reason that they are initially allocating so much memory, and is there a proper way of setting the image resource to avoid this memory waste?


Solution

  • Drawables in the drawable folder are treated as mdpi (i.e., 1x). Therefore the system will automatically upscale the image to the native density, growing it 3 times in size in each direction, for a total of 9x the memory usage.

    You should move the image to drawable-xxhdpi if you want the system to use it as its native resolution and the system will downscale it for lower density devices.

    If instead you want a fixed number of pixels on all densities (i.e., a different physical size on screen for different density devices), you can use the drawable-nodpi folder.