How Android Efficiently Displays Larger Bitmaps

  • 2021-07-18 08:57:59
  • OfStack

1. Load larger Bitmaps efficiently

Pictures come in a variety of shapes and sizes. In many cases, the actual size of the picture is much larger than the size displayed in the application. For example, the actual resolution of the picture displayed by the Gallery application included in the Android system is usually much higher than the density of the mobile phone device

Considering that we are developing an application with limited memory usage, ideally, we just want to load a low-resolution bitmap into memory. Generally speaking, this low-resolution bitmap should match the actual display size of UI components. A high-resolution picture does not bring us any obvious benefits, but it takes up valuable memory resources and incur additional performance overhead

2. Get the size and type of Bitmap

The BitmapFactory class provides us with several decoding methods (decodeByteArray (), decodeFile (), decodeResource (), etc) to create Bitmap from different sources, How to choose the most appropriate decode method depends on your image data source. These methods will try to apply memory to build Bitmap objects, All can easily lead to an OutOfMemory exception, Each type of decode method has an extra signature that allows you to specify the decoding option through the BitmapFactory. Options class. Setting the inJustDecodeBounds attribute to true when we are decoding avoids applying for memory. Although one null Bitmap object will be returned, the values of outWidth, outHeight and outMimeType and other attributes will be set for our incoming BitmapFactory. Options object. This technology allows you to know the size and type of Bitmap object in advance before building it.


BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inJustDecodeBounds = true; 
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, it is necessary to check the size and type of Bitmap before decoding Bitmap unless you really know exactly the size of Bitmap you want for decoding, and this size is suitable for the current application memory environment

3. Load a'reduced version 'of Bitmap into memory

Now that we know the size of the Bitmap, which will help us decide whether to load the whole Bitmap or the'scaled-down 'Bitmap, there are one factor to consider:

1. How much memory is expected to be used to load the whole picture

2. How much memory do you want to use for Bitmap when considering other memory requirements:

3. Size of ImageView controls or other UI components used to display Bitmap

4. Current device screen size and density

For example, one point is not worth loading a 1024x768 pixel picture into memory, and it will only be displayed on the 128x96 pixel ImageView control

We should tell decoder that the image needs to be sampled, load a smaller Bitmap into memory, and set the inSampleSize property of the BitmapFactory. Options object to true. For example, for a picture with a resolution of 2048x1536 pixels, if inSampleSize is set to 4 when decode, the final picture size is about 512x384, and it takes 0.75 M to load the memory instead of 12M when loading the whole picture (assuming that the bitmap is configured as ARGB_8888). Here is a method to calculate inSampleSize based on the target height and width


public static int calculateInSampleSize( 
   BitmapFactory.Options options, int reqWidth, int reqHeight) { 
 // Raw height and width of image 
 final int height = options.outHeight; 
 final int width = options.outWidth; 
 int inSampleSize = 1; 
 
 if (height > reqHeight || width > reqWidth) { 
  if (width > height) { 
   inSampleSize = Math.round((float)height / (float)reqHeight); 
  } else { 
   inSampleSize = Math.round((float)width / (float)reqWidth); 
  } 
 } 
 return inSampleSize; 
} 

NOTE: If the value of inSampleSize is a power of 2, it will be faster and more efficient for decoder. However, if you want to cache resized bitmaps to memory or hard disk, it still makes sense that decoding is the most suitable bitmap size, which helps to save memory or hard disk space

Here is a way to get a bitmap


public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 
  int reqWidth, int reqHeight) { 
 
 // First decode with inJustDecodeBounds=true to check dimensions 
 final BitmapFactory.Options options = new BitmapFactory.Options(); 
 options.inJustDecodeBounds = true; 
 BitmapFactory.decodeResource(res, resId, options); 
 
 // Calculate inSampleSize 
 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 
 
 // Decode bitmap with inSampleSize set 
 options.inJustDecodeBounds = false; 
 return BitmapFactory.decodeResource(res, resId, options); 
} 

This method makes it easy to load a bitmap in an UI component of any display size


mImageView.setImageBitmap( 
 decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100)); 

The above techniques for obtaining bitmaps are also required in other BitmapFactory. decode* series of decode methods.

The above is the whole content of this article, hoping to help you learn Android software programming.


Related articles: