In Android app development, we often need to deal with pictures, and pictures a very troublesome problem is the use of memory is very large, often lead to oom, understand bitmap related information, different SDK version of the Android image processing changes, And some of the ways to optimize the processing of our normal development in the picture will be very helpful.
This article first introduces bitmap basic content, about pixels, storing information, and loading.
Pixel
Bitmap storage can be said to include two parts, pixels and long, wide, color and other descriptive information. Pixels are the most memory-intensive place in the bitmap, where the length and pixel bits are used to describe the image, and this information calculates the memory size occupied by the image's pixels. The specific API to bitmap is the following interfaces:
publicfinalintgetWidth()publicfinalintgetHeight()publicfinalgetConfig()
The
Config is an enumeration type that represents a picture pixel type, with a total of the following types: alpha_8 (1), rgb_565 (3), argb_4444 (4), argb_8888 (5);
. Represents a picture of each pixel. In fact, the following two ways to get the values are equal:
int B = 1 ; switch (Bitmap.getconfig ()) {case alpha_8:b = 1 ; break ; case Argb_4444:b = 2 ; break ; case Argb_8888:b = 4 ; break ;} int bytes1 = bitmap.getwidth () * Bitmap.getheight () * b; int bytes2 = Bitmap.getbytecount (); //interface from api12
This is determined by the bitmap related parameters can calculate the number of pixels occupied by bitmap, in fact, we put in drawable inside the picture is already know the image of the length and width of the pixel composition, but directly on the outside of the Android image pixel count and the above code to calculate there will be a discrepancy. Because Android has scaled the image, this is related to the drawable location where you put the image.
We all know that there will be drawable-hdpi, drawable-xhdpi,drawable-xxhdpi and other directories in the Android resource directory. Each directory here will correspond to a density. Here's an example of the Bitmapfactory.decoderesource method loading bitmap:
BitmapFactory.Options options = new BitmapFactory.Options();Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test4, options);Log.i"options: " + options.inDensity"," + options.inTargetDensity);
Decoderesource is the Android internal to the resource load mode, here is not from the source above step by step introduction, it will eventually call Decoderesourcestream method, directly see Decoderesourcestream:
Public StaticBitmapDecoderesourcestream(Resources Res, typedvaluevalue, InputStream is, Rect pad, Options opts) {if(opts = =NULL) {opts =NewOptions (); }if(Opts.indensity = =0&&value!=NULL) {FinalintDensity =value. density;if(density = = Typedvalue.density_default) {opts.indensity = Displaymetrics.density_default; }Else if(Density! = Typedvalue.density_none) {opts.indensity = density; } }if(Opts.intargetdensity = =0&& Res! =NULL) {opts.intargetdensity = Res.getdisplaymetrics (). densitydpi; }returnDecodestream ( is, pad, opts);}
Options.indensity represents the default pixel density of the picture itself, Typedvalue will have a density that corresponds to which drawable directory the image is from, because each drawable directory (drawable-hdpi, DRAWABLE-XHDPI,DRAWABLE-XXHDPI) corresponds to a screen, and the screen has density,typedvalue density corresponding to Displaymetrics densitydpi, DENSITYDPI represents the number of pixels per foot. Options.intargetdensity is the densitydpi of the current phone screen, the final number of pixels is:
bytes = 原始图片宽*(options.inDensity/options.inTargetDensity)*原始图片长*(options.inDensity/options.inTargetDensity)*每个像素点位数
Storage and transport
Android images are not the same place to store in different SDK versions. Before 2.3 and 2.3, picture pixels were stored in native memory. Android memory is divided into Java heap and native memory. Android limits the maximum memory that each app can use. However, Android's memory limit is the Java heap and native memory, and the pixel data in the native area, the virtual machine can not automatically garbage collection, you must manually use Bitmap.recycle () to cause a very easy memory leak. Because Android device monitor can only see the memory changes in the Java heap, it is not easy to debug bitmap memory. For example, to create a new image in the app, you simply can't see the memory changes in the monitor.
Starting from 3.0 Android saves the picture in the Java heap, and when a new image is loaded, it can be immediately reflected from monitor. In addition, Java garbage collection mechanism can also be automatically recycled. Then after 4.0, the picture has some changes, that is, when the parcel transmission, when the picture is very large, it will use ASHMEM to carry out the transmission of the picture, specifically can see me this article Android4.0 after parcel transmission bitmap source analysis. In 6.0, the image of the storage has changed a lot, the bottom has been significantly increased the image to save Ashmem interface, specifically can see me this article Android6.0 bitmap storage and parcel transmission source analysis
Bitmapfactory
Bitmapfactory is used to load images, this class is mainly divided into three kinds of images loading, first take its API to look at:
Public StaticBitmapDecoderesourcestream(Resources Res, typedvaluevalue, InputStream is, Rect pad, Options opts) Public StaticBitmapDecoderesource(Resources Res,intID, Options opts) Public StaticBitmapDecoderesource(Resources Res,intId Public StaticBitmapDecodebytearray(byte[] Data,intOffsetintLength, Options opts) { Public StaticBitmapDecodebytearray(byte[] Data,intOffsetintLength) { Public StaticBitmapDecodeFile(String PathName, Options opts) Public StaticBitmapDecodeFile(String pathName) Public StaticBitmapDecodestream(InputStream is, Rect outpadding, Options opts) Public StaticBitmapDecodestream(InputStream is) Public StaticBitmapDecodefiledescriptor(FileDescriptor fd, Rect outpadding, Options opts) Public StaticBitmapDecodefiledescriptor(FileDescriptor FD)
We look directly at the Nativedecode interface provided by Bitmapfactory:
Private Static nativeBitmapNativedecodestream(InputStream is,byte[] storage, Rect padding, Options opts);Private Static nativeBitmapNativedecodefiledescriptor(FileDescriptor fd, Rect padding, Options opts);Private Static nativeBitmapNativedecodeasset(LongNativeasset, Rect padding, Options opts);Private Static nativeBitmapNativedecodebytearray(byte[] Data,intOffsetintLength, Options opts);
Bitmapfactory to file decode will be converted to InputStream Nativedecodestream to decode, resource will use Decode, And if Filedesciptor can be converted to native FD, it will decode through Nativedecodefiledescriptor, In addition ByteArray will directly use Nativedecodebytearray to decode. It is important to note that the resource decode,bitmapfactory will be set to the relevant parameters of option, and eventually the corresponding scaling, the size of the picture will be different from the original. specific content suggested to look at Bitmapfactory, understand the difference between each way, to be able to better use the interface, choose the time to adopt more efficient method.
Bitmapfactory.options
Let's take a look at the options class, we can use this parameter to do some processing on the image when loading, we have already said Indensity and intargetdensity. Look at the other parameters below.
Inpurgeable
The purpose of this parameter is to load the bitmap when the bitmap is needed, and to recycle the bitmap when it is not needed. In 4.1, with inpurgeable, the memory will not increase when the picture is loaded, but the memory is significantly increased without using inpurgeable to load the picture.
Insamplesize
This indicates the sample size, length and width will be multiplied by 1/insamplesize. Used to zoom out the picture so that the station occupies too much memory and is suitable for thumbnails.
Injustdecodebounds
This sets true to get the width length information for the picture. Here's an example:
BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;Bitmap bmp = BitmapFactory.decodeFile(path, options);// options.outWidth 和 options.outHeight就能够获取结果
This article primarily introduces BITMAP related basic information, bitmap,bitmapfactory and options classes, and Bitmap storage.
Android Bitmap in-depth introduction (i)---Foundation