Android Bulk loading picture oom problem Solutions

Source: Internet
Author: User

I. Scenarios and causes of the oom problem

A good app always has beautiful pictures, so the loading of images in Android development is always avoided, and in the process of loading pictures, if handled improperly, there will be oom problem. So how to solve this problem completely? This article will specifically describe this knowledge.

First, let's summarize that the oom scenario that appears during the loading of the picture is just a few things:

1, loading the picture too large

2. Too many pictures loaded at one time

3, the above two cases both have

So why is there an oom problem in the above scenario? In fact, the API documentation has a clear explanation, there are two main reasons for oMM :

1, mobile device will limit the memory that each app can use, the minimum is 16M, some devices will be allocated more, such as 24, 32M, 64M and so on, in short there will be restrictions, will not allow you unlimited use of the system.

2. In Andorid, pictures loaded into memory are stored as bitmaps, and argb_8888 is used by default after android2.3, in this way each pixel is stored using 4 bytes. So loading pictures is a lot of memory.

The scene and the reason we have all analyzed, let's look at how to solve these problems.

Second, solve the problem of large map loading

First of all to solve the problem of large map loading, generally in the actual application of the picture, because of the screen size and layout display reasons, we do not need to load the original large image, only to scale sample scaling. This is to save memory and to ensure that the picture is not distorted, the specific implementation steps are as follows:

1, on the basis of not loading the image content, to decode the image to get the size of the picture information

Here are the Bitmapfactory decode series methods and bitmapfactory.options that need to be used. When loading a picture using the Decode series method, be sure to set the Options Injustdecodebounds property to True.

    New bitmapfactory.options ();    Options.injustdecodebounds=true;    Bitmapfactory.decodefile (path, options);
2. Calculate the scale based on the size of the captured picture and the dimensions to be displayed in the interface.
 Public intcalculateinsamplesize (bitmapfactory.options Options,intReqwidth,intreqheight) {        //Raw Height and width of image        Final intHeight =Options.outheight; Final intwidth =Options.outwidth; intInsamplesize = 1; if(Height > Reqheight | | width >reqwidth) {            if(Width >height) {Insamplesize= Math.Round ((float) Height/(float) reqheight); } Else{insamplesize= Math.Round ((float) Width/(float) reqwidth); }        }        returninsamplesize; }
3. Scale the picture according to the calculated proportions.
// calculates the scale of the picture options.insamplesize=false; Bitmap Bitmap= bitmapfactory.decodefile (path, options);

Depending on the scale, you save a lot of memory than the original large image, as follows:

Three, bulk load large map

Let's take a look at how to bulk load a large map, first of all we mentioned above, according to the interface to show the size of the picture control to determine the scale of the picture. Here we use the GridView load local image As an example, the following steps:

1. Load all image addresses in external memory via system-provided ContentProvider
     Private void loadphotopaths () {        cursor cursornullnull NULL null);          while (Cursor.movetonext ()) {            = cursor.getstring (cursor.getcolumnindex (Mediacolumns.data));            Paths.add (path);        }        Cursor.close ();    }
2. Custom adapter, load picture in adapter GetView method
@Override PublicView GetView (intposition, View Convertview, ViewGroup parent) {Viewholder Holder=NULL; if(convertview==NULL) {Convertview= Layoutinflater.from ( This. Mcontext). Inflate (R.layout.grid_item_layout,NULL); Holder=NewViewholder (); Holder.photo=(ImageView) Convertview.findviewbyid (R.id.photo);        Convertview.settag (holder); }Else{Holder=(Viewholder) Convertview.gettag (); }                FinalString Path = This. Paths.get (position);        Holder.photo.setImageBitmap (Imageloader.getbitmapfromcache (path)); returnConvertview; }

After the key two steps above, we found that after the program ran, the user experience was particularly poor, half a day did not respond, it is obvious that this is because we load a large number of images in the main thread, this is not appropriate. Here we are going to put the loading of the picture into a sub-thread, to transform the custom Imageloader tool class and add a thread pool object for it to manage the child threads used to download the picture.

    PrivateExecutorservice executor; PrivateImageloader (Context mcontxt) {Super(); Executor= Executors.newfixedthreadpool (3); }    //an asynchronous method that loads a picture with a callback listener     Public voidLoadImage (FinalImageView View,FinalString Path,Final intReqwidth,Final intReqheight,FinalOnbitmaploadedlistener Callback) {                FinalHandler Mhandler =NewHandler () {@Override Public voidhandlemessage (Message msg) {Super. Handlemessage (msg); Switch(msg.what) { Case1: Bitmap Bitmap=(Bitmap) msg.obj;                    Callback.displayimage (view, bitmap);  Break; default:                     Break;                }            }                    }; Executor.execute (NewRunnable () {@Override Public voidrun () {Bitmap Bitmap=loadbitmapinbackground (Path, reqwidth, reqheight);                    Putbitmapinmemey (path, bitmap); Message msg= Mhandler.obtainmessage (1); Msg.obj=bitmap;            Mhandler.sendmessage (msg);    }        }); }

The user experience is significantly better after the transformation, as follows:

Although the effect has improved, there are two more serious problems in the loading process:

1, picture dislocation display

2, when we slide too fast, the picture loading speed is too slow

After analyzing the reason is not difficult to find out, mainly because we holder cache the grid item for reuse and the thread pool load task is caused by too many, only need to modify the program slightly, as follows:

adapte R:

  Holder.photo.setImageResource (R.drawable.ic_launcher);        Holder.photo.setTag (path); Imageloader.loadimage (Holder.photo, Path, densityutil.dip2px ( 80 80 new   Onbitmaploadedlistener () {@Override  
     
      public 
      void   DisplayImage (ImageView view, Bitmap Bitmap) {String imagePath  = View.get                Tag (). toString ();  if   (imagepath.equals (path)) {view.                Setimagebitmap (bitmap); }            }        });

Imageloader:

 Executor.execute (new   Runnable () {@Over Ride  public  void   run () {String key  = View.gettag (). toString ();                         if   (key.equals (path)) {                                Bitmap Bitmap  = Loadbitmapinbackground (path, Reqwidth,                        Reqheight);                        Putbitmapinmemey (path, bitmap);                        Message msg  = mhandler.obtainmessage (1 = bitmap;                    Mhandler.sendmessage (msg); }                }            });

For a better user experience, we can also continue to optimize, that is, to cache the image, we can be divided into two parts of the memory cache disk cache, this example loads the local image of all only memory cache. Continue modifying the Imageloader object to add the LRUCache object for caching the picture.

PrivateImageloader (Context mcontxt) {Super(); Executor= Executors.newfixedthreadpool (3); //Cache one-eighth of your app as a pictureActivitymanager am=(Activitymanager) Mcontxt.getsystemservice (Context.activity_service); intMaxSize = Am.getmemoryclass () *1024*1024/8; Mcache=NewLrucache<string, bitmap>(maxSize) {@Overrideprotected intsizeOf (String key, Bitmap value) {returnValue.getrowbytes () *value.getheight ();    }        }; }    //save picture to cache     Public voidPutbitmapinmemey (String path,bitmap Bitmap) {if(path==NULL)            return; if(bitmap==NULL)            return; if(Getbitmapfromcache (path) = =NULL){             This. Mcache.put (path, bitmap); }    }         PublicBitmap Getbitmapfromcache (String path) {returnmcache.get (path); }

Take the image from memory before loading the picture asynchronously in the LoadImage method, please download the case for the specific code.

Iv. Summary

summing up the problem of loading pictures with Oom is mainly the following methods:

1. Do not load the original large image, and then load its thumbnail after scaling according to the display control.

2, do not load the main thread of the picture, mainly in the ListView and the GridView using the asynchronous loading of the picture is to pay attention to deal with the picture dislocation and useless thread problem.

3, use the cache, according to the actual situation to determine whether to use double cache and cache size.

  

Do the little friends understand? If you want to test yourself, you can click "Download Project" to run the test!

Android Bulk loading picture oom problem Solutions

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.