Saturday, July 30, 2011

Down Sample Images to avoid Out of Memory Issues in Android

 

Out of Memory

Memory on phones are scarce. One of the most common case of out of memory (OOM) in Android development is loading images, specially when the source of the images are unknown.

Potential OOM operations include:

  • Loading a user specified image from the web
    • We don’ know the size/dimension of the image until it’s downloaded
  • Loading image from the gallery
    • Phone cameras capture images with very high resolution
    • Images will need to be rescaled for normal use

Note that Android allocated the Bitmap images with memory from the overall system, which means that even your application itself have plenty of memory available, OOM errors can still occurs because all the apps share the same memory pool for images (that are decoded with the BitmapFactory).

Downsampling

Downsampling reduce the resolution of an image by taking value of adjacent pixels and average them (a running average) to lower number of pixels.

Since the images in question are too large to be display on the phone regardless, the image is will be shrunk anyway when it’s displayed with a lower width ImageView. When this happens, we are simply wasting memory with loading unnecessarily large raw data.

Therefore, it’s more efficient to down sample the image during the initial load process.

Here’s a piece of code that does exactly that:

   1: private static Bitmap getResizedImage(String path, byte[] data, int targetWidth){
   2:     
   3:     BitmapFactory.Options options = new BitmapFactory.Options();
   4:     options.inJustDecodeBounds = true;
   5:     
   6:     BitmapFactory.decodeFile(path, options);
   7:     
   8:     int width = options.outWidth;
   9:     
  10:     int ssize = sampleSize(width, targetWidth);
  11:    
  12:    
  13:     options = new BitmapFactory.Options();
  14:     options.inSampleSize = ssize;
  15:     
  16:     Bitmap bm = null;
  17:     try{
  18:         bm = decode(path, data, options);
  19:     }catch(OutOfMemoryError e){
  20:         AQUtility.report(e);
  21:     }
  22:     
  23:     
  24:     return bm;
  25:     
  26: }
  27:  
  28: private static int sampleSize(int width, int target){
  29:     
  30:     int result = 1;
  31:     
  32:     for(int i = 0; i < 10; i++){
  33:         
  34:         if(width < target * 2){
  35:             break;
  36:         }
  37:         
  38:         width = width / 2;
  39:         result = result * 2;
  40:         
  41:     }
  42:     
  43:     return result;
  44: }

 

AQuery

With the AQuery lib for Android, downsampling is even simpler.

Down sample from the Internet

   1: String url = "http://farm6.static.flickr.com/5035/5802797131_a729dac808_b.jpg";            
   2: aq.id(R.id.image1).image(imageUrl, true, true, 200, 0);

 

Down sample image from File

   1: File file = new File(path);        
   2: //load image from file, down sample to target width of 300 pixels  
   3: aq.id(R.id.avatar).image(file, 300);

Checkout the image loading documentation for more detail.

Feedback

We hope our guide help your Android development.

If you have issues or have other insights regarding Android image loading / optimization, please feel free to leave a comment!

No comments:

Post a Comment