Bitmap fragment reuse open source library for any operation:Github.com/Dawish/Bitm…
The true face of Lushan
A Bitmap is not an image. People who are new to Android probably think that Bitmap is just an image, like me, hahaha, that’s what I thought when I first came to Android.
In a word:
Bitmap is a final class that implements the Parcelable interface. The new keyword cannot be used to create a Bitmap. Java function methods in Bitmap are basically implemented by calling native.
The word Bitmap is a bit and a map, just like our Java HashMap, which is just a special data store class.
The Bitmap class in Android is the data storage class for Android interface drawing. Our Canvas saves the drawn things in Bitmap and then hands them to the bottom layer for rendering. Since Bitmap needs to be passed in memory, this is also the reason for the implementation of Parcelable interface.
Second, Bitmap reuse
2.1 Storage Version Differences:
In Android 2.3.3 and earlier versions, bitmap pixel data is stored in Native memory, while bitmap objects are stored in Dalvik heap. Starting from Android 3.0, Pixel data is stored in the Dalvik Heap along with bitmap objects.
A few days ago, I saw that the latest Android O put Bitmap pixel data in Native memory again. You can refer to the article: www.cnblogs.com/xiaji5572/p…
2.2 Differences of reuse between different versions:
The inBitmap setting was introduced in Android 3.0. By setting this parameter, you can use a previously created Bitmap when loading images, but the size should be the same to save memory and avoid creating a new Bitmap. In Android4.4, inBitmap has been added to allow inBitmap to set the size of the image to be different from the image that needs to be loaded, as long as the inBitmap image is larger than the image that needs to be loaded.
2.3 Points for Reusing Bitmap
Bitmap multiplexing is preferred by requiring its mIsMutable property to be true, which means mutable
Controls whether the setPixel method of a Bitmap can be used, that is, whether the outside world can modify the pixels of a Bitmap. The mIsMutable property is true to modify the pixel data in a Bitmap, which makes it possible to reuse Bitmap objects.
How is this mIsMutable property assigned to true when creating a Bitmap?
1. Create a new Bitmap by using the createBitmap method mIsMutable property default to true
public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height, @NonNull Config config, boolean hasAlpha, @NonNull ColorSpace colorSpace) { ...... Nullptr color Spaces have a particular meaning in native and are interpreted as sRGB // unnecessary extra work of the else branch) if (config ! = Config. ARGB_8888 | | the colorSpace = = the colorSpace. Get (the colorSpace. Named. SRGB)) {/ * * * * * * * * * * eighth direct assignment mutable attribute to true * * * * * * * * * * / bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, null, null); } else { if (! (colorSpace instanceof ColorSpace.Rgb)) { throw new IllegalArgumentException("colorSpace must be an RGB color space"); } ColorSpace.Rgb rgb = (ColorSpace.Rgb) colorSpace; ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters(); if (parameters == null) { throw new IllegalArgumentException("colorSpace must use an ICC " + "parametric transfer function"); } ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50); **********/ bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, d50.getTransform(), parameters); }... Slightly}Copy the code
2. Use BitmapFactory and Options to decode a Bitmap by setting the Options decoding property to true
1 final BitmapFactory.Options options = new BitmapFactory.Options(); 2 //size must be 1; otherwise, an exception will be reported if the inBitmap attribute is used. 4 // this attribute must be used in SRC Bitmap decode, otherwise you can use which inBitmap attribute to decode the c++ level will raise an exception 5 //BitmapFactory: Unable to reuse an immutable bitmap as an image decoder target. 6 options.inMutable = true; InBitmap2 7 inBitmap2 = bitmapFactory.decodefile (path1,options); // Use the object inBitmap2 8 iv.setImageBitmap(inBitmap2); Options. inBitmap = inBitmap2; 10 long start=System.currentTimeMillis(); 11 iv2.setImageBitmap(BitmapFactory.decodeFile(path2,options)); 12 iv3.setImageBitmap(BitmapFactory.decodeFile(path3,options)); 13 iv4.setImageBitmap(BitmapFactory.decodeFile(path4,options));Copy the code
This reuse is written in comments.
2.4 Bitmap Reuse:
As you can see in the above code, retrieving a reusable bitmap from the cache assigns options.inBitmap to this bitmap when using the BitmapFactory to decode. This reuses the bitmap.
2. When an empty bitmap is needed, it can be obtained from the cache. The used bitmap can be placed in the LruCache cache. This allows us to retrieve a reusable bitmap setting from the LruCache cache to the Canvas
There is already an open source bitmap reuse project on Github github.com/amitshekhar… It is very simple to use.
The GlideBitmapPool open source project is used as follows:
Using Glide Bitmap Pool in your application
Add this in your build.gradle
The compile 'com. Amitshekhar. Android: glide - bitmap - the pool: first 0.0.1'Copy the code
Then initialize it in onCreate() Method of application class, :
GlideBitmapPool.initialize(10 * 1024 * 1024); // 10mb max memory size
Copy the code
Decoding the bitmap from file path
Bitmap bitmap = GlideBitmapFactory.decodeFile(filePath);
Copy the code
Decoding the bitmap from resources
Bitmap bitmap = GlideBitmapFactory.decodeResource(getResources(), R.drawable.testImage);
Copy the code
Decoding the down sample bitmap
Bitmap Bitmap = GlideBitmapFactory. DecodeFile (filePath, 100100);Copy the code
Making the bitmap available for recycle or reuse
GlideBitmapPool.putBitmap(bitmap);
Copy the code
Getting the empty bitmap from the pool
Bitmap bitmap = GlideBitmapPool.getBitmap(width, height, config);
Copy the code
Clearing or Trimming Memory
GlideBitmapPool.clearMemory();
GlideBitmapPool.trimMemory(level);
Copy the code
3. Arbitrary clipping in the case of reuse of Bitmap fragments
Fragmentation multiplexing refers to the creation and discarding of a large number of bitmaps during image clipping. If these bitmaps are not multiplexed, redundant memory will be wasted, resulting in memory jitter.
3.1 The remaining part of Bitmap clipping is reserved:
instructions | Comparison of effects before and after |
---|---|
Cut the lower part and take half the height | TIM picture 20180228220755. PNG After the cut: Screenshot_2018-02-28-21-59-16-052_BitmapKit.png |
Clipping code:
@param srcBitmap * @param needHeight * @param recycleSrc Whether to recycle the original map * @return */ @debuglog public static Bitmap cropBitmapBottom(Bitmap srcBitmap, int needHeight, boolean recycleSrc) { Log.d("danxx", "cropBitmapBottom before h : "+srcBitmap.getHeight()); /** needY = srcbitmap.getheight () -needheight; / * * * cut key steps/Bitmap cropBitmap = Bitmap. CreateBitmap (srcBitmap, 0, needY, srcBitmap getWidth (), needHeight); Log.d("danxx", "cropBitmapBottom after h : "+cropBitmap.getHeight()); RecycleSrc &&srcbitmap; = null && ! srcBitmap.equals(cropBitmap) && ! srcBitmap.isRecycled()) { GlideBitmapPool.putBitmap(srcBitmap); } return cropBitmap; }Copy the code
3.2 Bitmap clipping retains the left part:
instructions | Comparison of effects before and after |
---|---|
Trim the left part and take half the width | TIM picture 20180228220755. PNG After the cut: Screenshot_2018-02-28-21-59-34-089_BitmapKit.png |
Clipping code:
@param srcBitmap @param needWidth @return */ @debuglog public static Bitmap cropBitmapLeft(Bitmap srcBitmap, int needWidth, boolean recycleSrc) { Log.d("danxx", "cropBitmapLeft before w : "+srcBitmap.getWidth()); /** cropBitmap = bitmap.createBitMap (srcBitmap, 0, 0, needWidth, srcbitmap.getheight ()); Log.d("danxx", "cropBitmapLeft after w : "+cropBitmap.getWidth()); RecycleSrc &&srcbitmap; = null && ! srcBitmap.equals(cropBitmap) && ! srcBitmap.isRecycled()) { GlideBitmapPool.putBitmap(srcBitmap); } return cropBitmap; }Copy the code
3.3 Retain the right part of Bitmap clipping:
instructions | Comparison of effects before and after |
---|---|
Crop the right part and take half the width | TIM picture 20180228220755. PNG After the cut: Screenshot_2018-02-28-22-00-03-095_BitmapKit.png |
Clipping code:
@param srcBitmap @param needWidth @return */ @debuglog public static Bitmap cropBitmapRight(Bitmap srcBitmap, int needWidth, boolean recycleSrc) { Log.d("danxx", "cropBitmapRight before w : "+srcBitmap.getWidth()); int needX = srcBitmap.getWidth() - needWidth; /** cropBitmap = bitmap.createBitMap (srcBitmap, needX, 0, needWidth, srcbitmap.getheight ()); Log.d("danxx", "cropBitmapRight after w : "+cropBitmap.getWidth()); RecycleSrc &&srcbitmap; = null && ! srcBitmap.equals(cropBitmap) && ! srcBitmap.isRecycled()) { GlideBitmapPool.putBitmap(srcBitmap); } return cropBitmap; }Copy the code
3.4 Retain the upper part of Bitmap clipping:
instructions | Comparison of effects before and after |
---|---|
Cut the top part and take half the height | TIM picture 20180228220755. PNG After the cut: Screenshot_2018-02-28-21-59-49-769_BitmapKit.png |
Clipping code:
@param srcBitmap * @param needHeight * @param recycleSrc Whether to recycle the original map * @return */ @debuglog public static Bitmap cropBitmapTop(Bitmap srcBitmap, int needHeight, boolean recycleSrc) { Log.d("danxx", "cropBitmapBottom before h : "+srcBitmap.getHeight()); /** Cut the Y coordinates of the first pixel of the remaining upper part */ int needY = 0; / * * * cut key steps/Bitmap cropBitmap = Bitmap. CreateBitmap (srcBitmap, 0, needY, srcBitmap getWidth (), needHeight); Log.d("danxx", "cropBitmapBottom after h : "+cropBitmap.getHeight()); RecycleSrc &&srcbitmap; = null && ! srcBitmap.equals(cropBitmap) && ! srcBitmap.isRecycled()) { GlideBitmapPool.putBitmap(srcBitmap); } return cropBitmap; }Copy the code
3.5 Arbitrary clipping of specified parameters:
instructions | Comparison of effects before and after |
---|---|
Specify arbitrary clipping of parameters | TIM picture 20180228220755. PNG After the cut: Screenshot_2018-02-28-22-00-13-606_BitmapKit.png |
Clipping code:
/** * custom clipping, Trim * @param srcBitmap * @Param firstPixelX * @Param firstPixelY * @Param needWidth * @param needWidth * @param needHeight * @param recycleSrc * @return */ @DebugLog public static Bitmap cropBitmapCustom(Bitmap srcBitmap, int firstPixelX, int firstPixelY, int needWidth, int needHeight, boolean recycleSrc) { Log.d("danxx", "cropBitmapRight before w : "+srcBitmap.getWidth()); Log.d("danxx", "cropBitmapRight before h : "+srcBitmap.getHeight()); if(firstPixelX + needWidth > srcBitmap.getWidth()){ needWidth = srcBitmap.getWidth() - firstPixelX; } if(firstPixelY + needHeight > srcBitmap.getHeight()){ needHeight = srcBitmap.getHeight() - firstPixelY; } /** * cropBitmap = bitmap.createBitmap (srcBitmap, firstPixelX, firstPixelY, needWidth, needHeight); Log.d("danxx", "cropBitmapRight after w : "+cropBitmap.getWidth()); Log.d("danxx", "cropBitmapRight after h : "+cropBitmap.getHeight()); RecycleSrc &&srcbitmap; = null && ! srcBitmap.equals(cropBitmap) && ! srcBitmap.isRecycled()) { GlideBitmapPool.putBitmap(srcBitmap); } return cropBitmap; }Copy the code