1 page.title=Loading Large Bitmaps Efficiently 2 parent.title=Displaying Bitmaps Efficiently 3 parent.link=index.html 4 5 trainingnavtop=true 6 7 @jd:body 8 9 <div id="tb-wrapper"> 10 <div id="tb"> 11 12 <h2>This lesson teaches you to</h2> 13 <ol> 14 <li><a href="#read-bitmap">Read Bitmap Dimensions and Type</a></li> 15 <li><a href="#load-bitmap">Load a Scaled Down Version into Memory</a></li> 16 </ol> 17 18 <h2>Try it out</h2> 19 20 <div class="download-box"> 21 <a href="{@docRoot}shareables/training/BitmapFun.zip" class="button">Download the sample</a> 22 <p class="filename">BitmapFun.zip</p> 23 </div> 24 25 </div> 26 </div> 27 28 <p>Images come in all shapes and sizes. In many cases they are larger than required for a typical 29 application user interface (UI). For example, the system Gallery application displays photos taken 30 using your Android devices's camera which are typically much higher resolution than the screen 31 density of your device.</p> 32 33 <p>Given that you are working with limited memory, ideally you only want to load a lower resolution 34 version in memory. The lower resolution version should match the size of the UI component that 35 displays it. An image with a higher resolution does not provide any visible benefit, but still takes 36 up precious memory and incurs additional performance overhead due to additional on the fly 37 scaling.</p> 38 39 <p>This lesson walks you through decoding large bitmaps without exceeding the per application 40 memory limit by loading a smaller subsampled version in memory.</p> 41 42 <h2 id="read-bitmap">Read Bitmap Dimensions and Type</h2> 43 44 <p>The {@link android.graphics.BitmapFactory} class provides several decoding methods ({@link 45 android.graphics.BitmapFactory#decodeByteArray(byte[],int,int,android.graphics.BitmapFactory.Options) 46 decodeByteArray()}, {@link 47 android.graphics.BitmapFactory#decodeFile(java.lang.String,android.graphics.BitmapFactory.Options) 48 decodeFile()}, {@link 49 android.graphics.BitmapFactory#decodeResource(android.content.res.Resources,int,android.graphics.BitmapFactory.Options) 50 decodeResource()}, etc.) for creating a {@link android.graphics.Bitmap} from various sources. Choose 51 the most appropriate decode method based on your image data source. These methods attempt to 52 allocate memory for the constructed bitmap and therefore can easily result in an {@code OutOfMemory} 53 exception. Each type of decode method has additional signatures that let you specify decoding 54 options via the {@link android.graphics.BitmapFactory.Options} class. Setting the {@link 55 android.graphics.BitmapFactory.Options#inJustDecodeBounds} property to {@code true} while decoding 56 avoids memory allocation, returning {@code null} for the bitmap object but setting {@link 57 android.graphics.BitmapFactory.Options#outWidth}, {@link 58 android.graphics.BitmapFactory.Options#outHeight} and {@link 59 android.graphics.BitmapFactory.Options#outMimeType}. This technique allows you to read the 60 dimensions and type of the image data prior to construction (and memory allocation) of the 61 bitmap.</p> 62 63 <pre> 64 BitmapFactory.Options options = new BitmapFactory.Options(); 65 options.inJustDecodeBounds = true; 66 BitmapFactory.decodeResource(getResources(), R.id.myimage, options); 67 int imageHeight = options.outHeight; 68 int imageWidth = options.outWidth; 69 String imageType = options.outMimeType; 70 </pre> 71 72 <p>To avoid {@code java.lang.OutOfMemory} exceptions, check the dimensions of a bitmap before 73 decoding it, unless you absolutely trust the source to provide you with predictably sized image data 74 that comfortably fits within the available memory.</p> 75 76 <h2 id="load-bitmap">Load a Scaled Down Version into Memory</h2> 77 78 <p>Now that the image dimensions are known, they can be used to decide if the full image should be 79 loaded into memory or if a subsampled version should be loaded instead. Here are some factors to 80 consider:</p> 81 82 <ul> 83 <li>Estimated memory usage of loading the full image in memory.</li> 84 <li>Amount of memory you are willing to commit to loading this image given any other memory 85 requirements of your application.</li> 86 <li>Dimensions of the target {@link android.widget.ImageView} or UI component that the image 87 is to be loaded into.</li> 88 <li>Screen size and density of the current device.</li> 89 </ul> 90 91 <p>For example, its not worth loading a 1024x768 pixel image into memory if it will eventually be 92 displayed in a 128x96 pixel thumbnail in an {@link android.widget.ImageView}.</p> 93 94 <p>To tell the decoder to subsample the image, loading a smaller version into memory, set {@link 95 android.graphics.BitmapFactory.Options#inSampleSize} to {@code true} in your {@link 96 android.graphics.BitmapFactory.Options} object. For example, an image with resolution 2048x1536 that 97 is decoded with an {@link android.graphics.BitmapFactory.Options#inSampleSize} of 4 produces a 98 bitmap of approximately 512x384. Loading this into memory uses 0.75MB rather than 12MB for the full 99 image (assuming a bitmap configuration of {@link android.graphics.Bitmap.Config ARGB_8888}). Heres 100 a method to calculate a the sample size value based on a target width and height:</p> 101 102 <pre> 103 public static int calculateInSampleSize( 104 BitmapFactory.Options options, int reqWidth, int reqHeight) { 105 // Raw height and width of image 106 final int height = options.outHeight; 107 final int width = options.outWidth; 108 int inSampleSize = 1; 109 110 if (height > reqHeight || width > reqWidth) { 111 112 // Calculate ratios of height and width to requested height and width 113 final int heightRatio = Math.round((float) height / (float) reqHeight); 114 final int widthRatio = Math.round((float) width / (float) reqWidth); 115 116 // Choose the smallest ratio as inSampleSize value, this will guarantee 117 // a final image with both dimensions larger than or equal to the 118 // requested height and width. 119 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 120 } 121 122 return inSampleSize; 123 } 124 </pre> 125 126 <p class="note"><strong>Note:</strong> Using powers of 2 for {@link 127 android.graphics.BitmapFactory.Options#inSampleSize} values is faster and more efficient for the 128 decoder. However, if you plan to cache the resized versions in memory or on disk, its usually still 129 worth decoding to the most appropriate image dimensions to save space.</p> 130 131 <p>To use this method, first decode with {@link 132 android.graphics.BitmapFactory.Options#inJustDecodeBounds} set to {@code true}, pass the options 133 through and then decode again using the new {@link 134 android.graphics.BitmapFactory.Options#inSampleSize} value and {@link 135 android.graphics.BitmapFactory.Options#inJustDecodeBounds} set to {@code false}:</p> 136 137 <a name="decodeSampledBitmapFromResource"></a> 138 <pre> 139 public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 140 int reqWidth, int reqHeight) { 141 142 // First decode with inJustDecodeBounds=true to check dimensions 143 final BitmapFactory.Options options = new BitmapFactory.Options(); 144 options.inJustDecodeBounds = true; 145 BitmapFactory.decodeResource(res, resId, options); 146 147 // Calculate inSampleSize 148 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 149 150 // Decode bitmap with inSampleSize set 151 options.inJustDecodeBounds = false; 152 return BitmapFactory.decodeResource(res, resId, options); 153 } 154 </pre> 155 156 <p>This method makes it easy to load a bitmap of arbitrarily large size into an {@link 157 android.widget.ImageView} that displays a 100x100 pixel thumbnail, as shown in the following example 158 code:</p> 159 160 <pre> 161 mImageView.setImageBitmap( 162 decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100)); 163 </pre> 164 165 <p>You can follow a similar process to decode bitmaps from other sources, by substituting the 166 appropriate {@link 167 android.graphics.BitmapFactory#decodeByteArray(byte[],int,int,android.graphics.BitmapFactory.Options) 168 BitmapFactory.decode*} method as needed.</p> 169