Android those bitmap objects you don't know

Source: Internet
Author: User

Reprint please indicate this article from Xiaanming's blog (http://blog.csdn.net/xiaanming/article/details/41084843), please respect others ' hard work results, thank you!

We know that the memory allocated to each application by the Android system is limited, and bitmap as a major drain on memory, and our management of bitmap may lead to OutOfMemoryError, There are some differences between the bitmap objects in different versions of Android, so let's introduce these differences today and provide some of the things you need to be aware of when using bitmap.

In Android2.3.3 (API 10) and previous versions, bitmap objects are stored separately from their pixel data, bitmap objects are stored in the Dalvik heap, and the bitmap object's pixel data is stored in native Memory (local RAM) or derict memory (direct RAM), which makes the release of pixel data stored in native memory unpredictable, we can call the Recycle () method to native The pixel data in memory is released, as long as you can clearly determine that bitmap is no longer in use, and if you call the Bitmap object Recycle () and then draw the bitmap, the canvas:trying to use a Recycled Bitmap "error, and after Android3.0 (API 11), the bitmap pixel data and the bitmap object are stored in the Dalvik heap, so we don't have to manually call recycle () to release the Bitmap object, The release of the memory to the garbage collector to do, perhaps you will ask, why do I display bitmap object when still appear OutOfMemoryError?

Before I say this, I mention that before Android2.2 (API 8), using the serial garbage collector, from the name can be seen as a single-threaded collector, where the "single-threaded" means not just using a CPU or a collection thread to collect garbage, More importantly, when it is garbage collected, all other worker threads must be paused, and after Android2.3, the collector is replaced with a concurrent garbage collector, which means that our garbage collection threads and our worker threads do not affect each other.

After a simple understanding of the garbage collector, we give a simple example of the above problem, if the system started the garbage collection thread to collect garbage, and at this time we produce a large number of bitmap objects, it is possible to produce outofmemoryerror, Because the garbage collector first to determine whether an object is still alive (the Java language to determine whether the object is surviving using the root search algorithm GC root tracing), and then use garbage collection algorithm to garbage collection, different garbage collector has a different recycling algorithm, which will take time, In the event of a outofmemoryerror, we have to make it clear that the memory leak (Leak) is the result of a memory overflow (memories overflow), and if it is a memory leak we need tools (like mat) Find out the memory leak code and make corrections, if there is no leakage, in other words is the memory of the object really must still live, then we can see if there is a way to reduce the memory consumption of objects, such as when we use bitmap, Should be based on the size of the view bitmapfactory.options calculate the appropriate insimplesize to the bitmap to the corresponding clipping, to reduce the use of memory bitmap, if it is done or there is outofmemoryerror (This is rarely the case), then we can only increase the size of the Dalvik heap, in Android 3.1 and later, we can add a value in Androidmanifest.xml's application tag equal to "true" Android:largeheap property to notify the Dalvik virtual machine application that a larger Java Heap is required, but we do not encourage this.


Manage bitmap on Android 2.3 and below

From the above we know that in Android2.3 and below we recommend using the Recycle () method to free memory, when we use the ListView or GridView, when to call the Recycle ()? Here we use a reference count, using a variable (dispalyrefcount) to record the bitmap display, if the bitmap is plotted on the view Displayrefcount plus one, or minus one, We need to bitmap () the Recycle object only if Displayrescount is 0 and bitmap is not empty and bitmap has not called recycle (), so we want to wrap the bitmap object in a class, the code is as follows

Package Com.example.bitmap;import Android.content.res.resources;import Android.graphics.bitmap;import Android.graphics.drawable.bitmapdrawable;public class Recyclebitmapdrawable extends bitmapdrawable {private int    Displayrescount = 0;private Boolean mhasbeendisplayed;    Public Recyclebitmapdrawable (Resources res, Bitmap Bitmap) {super (res, BITMAP); }/** * @param isdisplay */public void setisdisplayed (Boolean isdisplay) {synchronized (this) {if (Isdisplay) {mhasbeendisplayed = True;displayrescount + +;} Else{displayrescount--;}} CheckState ();} /** * Check some status of the picture to determine if you need to call recycle */private synchronized void CheckState () {if (displayrescount <= 0 && MHASB    eendisplayed && Hasvalidbitmap ()) {Getbitmap (). Recycle (); }}/** * Determine if Bitmap is empty and has called recycle () * @return */private synchronized Boolean hasvalidbitmap () {Bitmap Bitmap = Getbitm    AP (); return bitmap! = null &&!bitmap.isrecycled ();}}
In addition to the above recyclebitmapdrawable, we also need a custom imageview to control when to show bitmap and when to hide bitmap objects

Package Com.example.bitmap;import Android.content.context;import Android.graphics.drawable.drawable;import Android.graphics.drawable.layerdrawable;import Android.util.attributeset;import Android.widget.ImageView;public Class Recycleimageview extends ImageView {public Recycleimageview (context context) {super (context);} Public Recycleimageview (context context, AttributeSet Attrs) {Super (context, attrs);} Public Recycleimageview (context context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle);} @Overridepublic void setimagedrawable (drawable drawable) {drawable previousdrawable = getdrawable (); Super.setimagedrawable (drawable);//Displays the new Drawablenotifydrawable (drawable, true);//The picture before recycling notifydrawable ( Previousdrawable, false);} @Overrideprotected void Ondetachedfromwindow () {//When the view is detached from the window, clear drawablesetimagedrawable (null); Super.ondetachedfromwindow ();} /** * Notify the drawable to show or hide * * @param drawable * @param isdisplayed */public static void Notifydrawable (Drawable drawable, b Oolean IsDisplayed) {if (drawable instanceof recyclebitmapdrawable) {((recyclebitmapdrawable) drawable). setIsDisplayed ( isdisplayed);} else if (drawable instanceof layerdrawable) {layerdrawable layerdrawable = (layerdrawable) drawable;for (int i = 0, z = LA Yerdrawable.getnumberoflayers (); I < Z; i++) {notifydrawable (layerdrawable.getdrawable (i), isdisplayed);}}}}
This custom class is also relatively simple, rewrite the setimagedrawable () method, in this method we first get ImageView above the picture, and then notify before the drawable displayed in ImageView is not displayed, Drawable will determine if it is necessary to call recycle (), and when the view is detached from the window, it will callback Ondetachedfromwindow (), and in this method we recycle the images displayed in ImageView, using the method

ImageView ImageView = new ImageView (context); Imageview.setimagedrawable (New Recyclebitmapdrawable ( Context.getresource (), bitmap));
Only need to use recyclebitmapdrawable packaging Bitmap object, and then set to ImageView above can, specific memory release we do not need to tube, is not very convenient? This is the memory in Android2.3 and the following version management bitmap.


Manage bitmap on Android 3.0 and above

Since bitmap's pixel data is also stored in the Dalvik heap in Android3.0 and above, the management of the memory is given directly to the garbage collector, and we do not need to manually release the memory. And today is mainly BitmapFactory.Options.inBitmap this field, if this field is set, when we decode bitmap, he will reuse Inbitmap set bitmap, reduce the allocation and release of memory, improve the performance of the application, but in Andro Before ID 4.4, BitmapFactory.Options.inBitmap set bitmap must match the size of the bitmap we need to decode, after Android4.4, BitmapFactory.Options.inBitmap set bitmap greater than or so We need to decode the size of the bitmap is OK, we first assume a scene, or use Listview,gridview to load a large number of images, in order to improve the efficiency of the application, we usually do the corresponding memory cache and hard disk cache, here we only say memory cache, While the memory cache is officially recommended to use LRUCache, note that LRUCache only acts as a cache data and does not reclaim memory. In general, our code will write this.

Package Com.example.bitmap;import Java.lang.ref.softreference;import Java.util.collections;import Java.util.hashset;import Java.util.iterator;import Java.util.set;import Android.annotation.targetapi;import Android.graphics.bitmap;import Android.graphics.bitmap.config;import Android.graphics.bitmapfactory;import Android.graphics.drawable.bitmapdrawable;import Android.os.build;import Android.os.build.version_codes;import Android.support.v4.util.lrucache;public class Imagecache {private final static int max_memory = 4 * 102 * 1024;private Lru Cache<string, bitmapdrawable> mmemorycache;private set<softreference<bitmap>> mReusableBitmaps; private void init () {if (Hashoneycomb ()) {mreusablebitmaps = Collections.synchronizedset (New hashset<softreference <Bitmap>> ());} Mmemorycache = new lrucache<string, bitmapdrawable> (max_memory) {/** * The callback method when the saved Bitmapdrawable object is removed from the LRUCache */@Overrideprotected void entryremoved (Boolean evicted, String key, BitmapdrawableOldValue, bitmapdrawable newvalue) {if (Hashoneycomb ()) {Mreusablebitmaps.add (New softreference<bitmap> ( Oldvalue.getbitmap ()));}}};} /** * from Mreusablebitmaps to get the Bitmap object that can be set to BitmapFactory.Options.inBitmap above * @param Options * @return */protected Bitmap Getbitmapfromreusableset (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 ()) {if (ca Nuseforinbitmap (item, Options)) {bitmap = Item;iterator.remove (); break;}} else {iterator.remove ();}}}} return bitmap;} /** * Determine if the bitmap can be set to BITMAPFACTORY.OPTIONS.INBITMAP * * @param candidate * @param targetoptions * @return */@TargetApi ( Version_codes. KITKAT) public static Boolean Canuseforinbitmap (Bitmap candidate,bitmapfactory.options TargetoptiONS) {//After Anroid4.4, if you want to use Inbitmap, you only need to decode the bitmap smaller than the Inbitmap settings, there is no limit to insamplesize//if (Build.VERSION.SDK_INT >= Build.version_codes. KITKAT) {int width = targetoptions.outwidth/targetoptions.insamplesize;int height = targetoptions.outheight/targetopt Ions.insamplesize;int byteCount = width * height* getbytesperpixel (Candidate.getconfig ()); return ByteCount <= Candidate.getallocationbytecount ();} Before android//4.4, if you want to use Inbitmap, the decoded bitmap must be equal to the width of the Inbitmap setting, and Insamplesize is 1return candidate.getwidth () = = targetoptions.outwidth&& candidate.getheight () = = targetoptions.outheight&& Targetoptions.insamplesize = = 1;} /** * Gets the number of bytes consumed per pixel * * @param config * @return */public static int getbytesperpixel (config config) {if (config = = Conf Ig. argb_8888) {return 4;} else if (config = = config.rgb_565) {return 2;} else if (config = = config.argb_4444) {return 2;} els e if (config = = config.alpha_8) {return 1;} return 1;} @TargetApi (version_codes. Honeycomb) public static Boolean Hashoneycomb () {return Build.VERSION.SDK_INT >= build.version_codes. Honeycomb;}}
The above is just some example code that saves a weak reference to the Bitmapdrawable object removed from LRUCache in a set. The bitmap object satisfying the BitmapFactory.Options.inBitmap condition is then obtained from the set to improve the decoding bitmap performance, using the following

public static Bitmap decodesampledbitmapfromfile (String filename,        int reqwidth, int reqheight) {    final Bitmapfactory.options Options = new Bitmapfactory.options ();    ...    Bitmapfactory.decodefile (filename, options);    ...    If we ' re running on honeycomb or newer, try to use Inbitmap.    if (Imagecache.hashoneycomb ()) {     options.inmutable = true;        if (cache! = null) {            Bitmap inbitmap = cache.getbitmapfromreusableset (options);            if (inbitmap! = null) {                options.inbitmap = Inbitmap;}}    }    ...    return bitmapfactory.decodefile (filename, options);}

Through this article you are not bitmap object has a further understanding, when the application load a large number of bitmap objects, if you do the above points, I believe that the application occurs OutOfMemoryError probability will be very small, and performance will be a certain increase, I often see some students in the evaluation of a picture loading frame is not good, more one-sided with their own use in the process of whether or not outofmemoryerror to the conclusion, of course recurring OutOfMemoryError you should first check your code for problems, Generally some more mature framework is not a very serious problem, after all, it has been a lot of testing before it is well-known, today's explanation is here, students with doubts can leave a message below!




Android those bitmap objects you don't know

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.