In addition to caching bitmap, there are other things you can do to optimize the reuse of GC and bitmap. The recommended strategy depends on the Android version of the system. The examples in the attachment show you how to design your app to improve the memory performance of your app in different versions of Android. in different versions of Android, Bitmap's memory management is different. in Android2.2 (API Level8) and previous versions, the main thread of the app will be stopped when the GC is triggered. This leads to a noticeable lag and reduces the user experience. The concurrent GC has been added from Android2.3, which means that as long as the bitmap is no longer referenced, the memory will be recycled immediately. in Android2.3.3 (API level 10) and previous versions, Bitmap's pixel data is kept in the underlying memory, and bitmap itself is stored in the heap of the virtual machine. The collection of pixel data stored in the underlying memory is unpredictable, which can easily cause the app to exceed memory limits and crash. After Android3.0, the bitmap and associated pixel data are saved in the heap of the virtual machine. Below you will learn how to optimize bitmap memory in different versions of Android. 1. Managing memory in Android2.3.3 and previous versions. in Android2.3.3 and earlier versions, it is recommended to use the Recycle () method to manage memory. If a large picture is displayed in the app, it is likely to cause a OutOfMemoryError exception. The Recycle () method allows the app to reclaim memory as soon as possible. It is important to note that the Recycle () method can only be called when you are sure that bitmap will not be used again. If you subsequently display a bitmap that has already called the Recycle () method, you will get the "canvas:trying to use a recycled bitmap" exception. The following code snippet shows an example of calling the Recycle () method. The reference count is used here to track what is now beingThe bitmap (variables Mdisplayrefcount and mcacherefcount) that are shown and are being buffered. Picture recycling will be performed when the following two conditions are met. 1) Mdisplayrefcount and Mcacherefcount are also 0. 2) bitmap is not null and the Recycle () method has not been called.
private int mcacherefcount = 0;private int mdisplayrefcount = 0;...//drawable The display state has changed.//Keep a count to determine when The drawable is no longer displayed.public void Setisdisplayed (Boolean isdisplayed) {synchronized (this) {if ( isdisplayed) {mdisplayrefcount++; Mhasbeendisplayed = true; } else {mdisplayrefcount--; }}//Check to see if recycle () can is called. CheckState ();} Notify the drawable, the cache state have changed.//Keep a count to determine when the drawable is no longer being Cached.public void Setiscached (Boolean iscached) {synchronized (this) {if (iscached) {Mcacherefcou nt++; } else {mcacherefcount--; }}//Check to see if recycle () can is called. CheckState ();} Private synchronized void CheckState () {//If the drawable cache and display ref counts = 0, and this drawable//h As been displayed, then recycle. if (McacherefcounT <= 0 && mdisplayrefcount <= 0 && mhasbeendisplayed && hasvalidbitmap ()) { Getbitmap (). Recycle (); }}private synchronized Boolean hasvalidbitmap () {Bitmap Bitmap = Getbitmap (); return bitmap! = null &&!bitmap.isrecycled ();}2. Managing Android3.0 and later versions of memoryAndroid3.0 (API level 11) Added the BitmapFactory.Options.inBitmap field. If this option is set, then the Decode method using the options will attempt to re-use an existing bitmap to load the new bitmap. This means that bitmap's memory will be reused to avoid allocating and freeing memory to improve performance. Then, there are some restrictions on using INBITMAP. Especially before Android4.4 (API level19), only bitmap of the same size can use this feature. The following code snippet shows how to save an existing bitmap in the app for later reuse. The app runs in Android3.0 and later, and when Bitmap is released by LRUCache, a hashset is used to hold a soft reference to the bitmap (Soft Reference) for future use by Inbitmap.
Set<softreference<bitmap>> mreusablebitmaps;private lrucache<string, BitmapDrawable> mmemorycache;//If you ' re running on honeycomb or newer, create a//synchronized HashSet of references to reusable bitmaps . if (Utils.hashoneycomb ()) {mreusablebitmaps = Collections.synchronizedset (New hashset<softreference< Bitmap>> ());} Mmemorycache = new lrucache<string, bitmapdrawable> (mcacheparams.memcachesize) {//Notify the removed entry that is no longer being cached. @Override protected void Entryremoved (Boolean evicted, String key, Bitmapdrawable OldValue, bitmapdrawable N Ewvalue) {if (RecyclingBitmapDrawable.class.isInstance (OldValue)) {//The removed entry is a recycling Drawable, so notify it//that it had been removed from the memory cache. ((recyclingbitmapdrawable) oldValue). Setiscached (false); } else {//The removed entry is a standard bitmapdrawable. if (Utils.hashoneycomb ()) {//We ' re running on honeycomb or later, so add the bitmap To a softreference set is possible use with Inbitmap later. Mreusablebitmaps.add (New softreference<bitmap> (Oldvalue.getbitmap ())); } } }....}In the app run,the following methods check for the existence of bitmap that can be reused.
public static Bitmap decodesampledbitmapfromfile (String filename, int reqwidth, int reqheight, Imagecache cache) { c5/>final bitmapfactory.options Options = new Bitmapfactory.options (); ... Bitmapfactory.decodefile (filename, options); ... If we ' re running on honeycomb or newer, try to use Inbitmap. if (Utils.hashoneycomb ()) { addinbitmapoptions (options, cache); } ... return bitmapfactory.decodefile (filename, options);}
The Addinbitmapoptions () method in the above code is specifically implemented as follows. It is used to find an existing bitmap used to set the inbitmap field. Note that this method will only set the inbitmap field if the appropriate bitmap is found (your code should not assume that you can always find a match).
private static void Addinbitmapoptions (Bitmapfactory.options Options, Imagecache cache) {//Inbitmap only works With mutable bitmaps, so force the decoder to//return mutable bitmaps. Options.inmutable = true; if (cache! = NULL) {//Try to find a bitmap to use for Inbitmap. Bitmap inbitmap = cache.getbitmapfromreusableset (options); if (inbitmap! = null) {//If a suitable bitmap has been found, set it as the value of//Inbitmap. Options.inbitmap = Inbitmap; }}}//This method iterates through the reusable bitmaps, looking-one//to use for inbitmap:protected Bitmap GETBI Tmapfromreusableset (bitmapfactory.options Options) {Bitmap Bitmap = null; if (mreusablebitmaps! = null &&!mreusablebitmaps.isempty ()) {synchronized (mreusablebitmaps) { Final iterator<softreference<bitmap>> Iterator = Mreusablebitmaps.iterator (); BitmAP Item; while (Iterator.hasnext ()) {item = Iterator.next (). get (); if (null! = Item && item.ismutable ()) {//Check to see it the item can is used for inbitmap. if (Canuseforinbitmap (item, Options)) {bitmap = Item; Remove from reusable set so it can ' t be used again. Iterator.remove (); Break }} else {//Remove from the set if the reference have been cleared. Iterator.remove (); }}}} return bitmap;} Finally, the following method is used to determine whether the current bitmap meets the size requirements of the inbitmap.
Static Boolean Canuseforinbitmap (Bitmap candidate, bitmapfactory.options targetoptions) {if (Build.VERSION.SDK _int >= build.version_codes. KITKAT) {//From Android 4.4 (KITKAT) onward we can re-use if the byte size in//The new bitmap is smaller than the reusable bitmap candidate//allocation byte count. int width = targetoptions.outwidth/targetoptions.insamplesize; int height = targetoptions.outheight/targetoptions.insamplesize; int byteCount = width * Height * getbytesperpixel (candidate.getconfig ()); return ByteCount <= candidate.getallocationbytecount (); }//On earlier versions, the dimensions must match exactly and the insamplesize must be 1 return candidate.getwidth () = = Targetoptions.outwidth && candidate.getheight () = = Targetoptions.outheight && Targetoptions.insamplesize = = 1;} /** * A helper function to return the byte usage per pixel of A bitmap based in its Configuration. */static int getbytesperpixel (config config) {if (config = = config.argb_8888) {return 4; } else if (config = = config.rgb_565) {return 2; } else if (config = = config.argb_4444) {return 2; } else if (config = = config.alpha_8) {return 1; } return 1;}
This article is translated from the official Android document, the original address is http://developer.android.com/training/displaying-bitmaps/manage-memory.html
Android Management bitmap Memory