Original address: http://android.xsoftlab.net/training/displaying-bitmaps/index.html
Introduction
Learn how to use a conventional means of handling and loading bitmap objects, which in addition to making the user interface responsive, avoids exceeding the memory limit. If you're not careful, the bitmap will quickly deplete those poor memory and cause the program to crash because it will produce a horrible exception:
java.lang.OutofMemoryError: bitmap size exceeds VM budget.
Here are some reasons why loading bitmaps is tricky for Android apps:
- Mobile devices often contain limited resources. Android devices have only a small amount of 16MB of available memory for a single program. Virtual machine compatibility (VM compatibility) gives minimal program memory requirements for various screen sizes and densities. The program should take full advantage of the memory space in a very small amount of memory space. Keep in mind, however, that many devices are equipped with higher limits.
- Bitmaps usually consume a lot of memory, especially rich images, like photos. For example, the camera on the Galaxy Nexus will take a picture of 2592x1936 pixels (5 million pixels). If the bitmap configuration uses argb_8888 (which is the default before Android 2.3), loading this photo into memory consumes 19MB of memory (2592*1936*4 bytes), which immediately drains all memory on some devices.
- Android's app interface sometimes requests some images to load frequently. Some components, such as the ListView, GridView, and Viewpager, have a common feature that requires multiple bitmaps to be loaded on the screen at the same time and will be loaded outside the screen to show when the finger is sliding.
Load large image effectively
Pictures are available in various shapes and sizes. In many cases they will be larger than the size required on the user interface. For example, the system's photo album application shows a camera-taken photograph with a resolution that is usually higher than the screen's density.
Given the limited in-memory work, it is ideal to load a low-resolution version only. The low-resolution version should match the size of the control that shows the image. The higher resolution of the picture does not have a visually better effect, but it still consumes valuable memory space, which incurs additional performance overhead due to the additional dynamic expansion.
This session discusses the process of sampling a large bitmap two times and loading the sampled iteration into memory. This process does not exceed the application's memory limit.
Reading the size and type of bitmaps
Class Bitmapfactory provides several decoding methods (Decodebytearray (), DecodeFile (), Decoderesource (), etc.) Creates a bitmap bitmap based on a different resource. Choosing a more appropriate decoding method depends on the data resource of the picture. These methods attempt to request space to the memory when constructing the bitmap, so the outofmemory exception is easily caused. Each decoding method has a subordinate feature that allows you to specify decoding options through the Bitmapfactory.options class. Set the Injustdecodebounds property to true to avoid requesting space for memory when decoding, which returns an empty bitmap, except for Outwidth, Outheight, and Outmimetype settings. This technique allows you to read the size and type of the image data in advance before constructing the bitmap (requesting memory).
newtrue;BitmapFactory.decodeResource(getResources(), R.id.myimage, options);int imageHeight = options.outHeight;int imageWidth = options.outWidth;String imageType = options.outMimeType;
To avoid java.lang.OutOfMemory exceptions, you need to check the size of the image before decoding it, unless you absolutely trust the size of the image data, and that size is good for available memory.
Load a reduced version to memory
So now the size of the picture is known, and this size can be used to decide whether the full-size image should be loaded into memory or should have a two-sample version loaded into memory. Here are some factors to consider:
- Loading full-size images into memory should estimate the amount of memory to use.
- The amount of memory required to load the picture needs to be reserved for the application to a certain memory space, do not consume completely.
- The size of the ImageView or UI component is the size to which the image will be loaded.
- The screen size and density of the current device.
For example, loading a picture of a 1024x768 pixel into memory is worthless if the image is eventually displayed as a 128x96 pixel thumbnail.
To tell the decoder that it needs to be sampled two times to load a small version of the image into memory, you need to set the Insamplesize property of the Bitmapfactory.options object to True. For example, a picture with a resolution of 2048x1536, which needs to be decoded by insamplesize to a size of 4 bitmap, is probably 512x384. Loading such an image requires only 0.75MB of memory, while a full-size image takes 12MB of memory (assuming the bitmap is configured as argb_8888). Here is a way to calculate a sample capacity value, which is a power of 2 and is calculated based on the height and width values of the original image.
Public Static int calculateinsamplesize(Bitmapfactory.options Options,intReqwidth,intReqheight) {//Raw height and width of image Final intHeight = options.outheight;Final intwidth = options.outwidth;intInsamplesize =1;if(Height > Reqheight | | width > reqwidth) {Final intHalfheight = height/2;Final intHalfwidth = width/2;//Calculate The largest insamplesize value is a power of 2 and keeps both //height and width larger than the requested height and width. while(halfheight/insamplesize) > Reqheight && (halfwidth/insamplesize) > Reqwidth) {Insamplesize *=2; } }returnInsamplesize;}
Note: The final computed value is a power of 2 because the decoder needs to be rounded to get a final value that is closest to the power of 2, according to the Insamplesize document.
In order to use this method, the first step is to set Injustdecodebounds to true, and then give the options to bitmapfactory to use, Then use again with a new insamplesize and injustdecodebounds set to False to use again:
Public StaticBitmapDecodesampledbitmapfromresource(Resources Res,intResId,intReqwidth,intReqheight) {//First decode with injustdecodebounds=true to check dimensions FinalBitmapfactory.options Options =NewBitmapfactory.options (); Options.injustdecodebounds =true; Bitmapfactory.decoderesource (res, resId, options);//Calculate insamplesizeOptions.insamplesize = calculateinsamplesize (options, Reqwidth, reqheight);//Decode bitmap with Insamplesize setOptions.injustdecodebounds =false;returnBitmapfactory.decoderesource (res, resId, options);}
This method can easily load any large size bitmap to ImageView, this imageview shows a 100*100 pixel thumbnail, as shown in the following code:
mImageView.setImageBitmap( 100100));
You can follow a similar process to decode other resources and, if necessary, replace the appropriate bitmapfactory.decode* method.
Android Official Development Document Training Series Course Chinese version: efficient display of bitmap loading large bitmap