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.

    Bitmapfactory.options Options = 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 int calculateinsamplesize (bitmapfactory.options Options,            int reqwidth, int reqheight) {        //Raw height and Width of image        final int height = options.outheight;        Final int width = options.outwidth;        int insamplesize = 1;        if (Height > Reqheight | | width > reqwidth) {            if (width > height) {                insamplesize = Math.Round (float) Hei Ght/(float) reqheight);            } else {                insamplesize = Math.Round ((float) width/(float) reqwidth);            }        }        return insamplesize;    }
3. Scale the picture according to the calculated proportions.
Calculate the scale of the picture options.insamplesize = calculateinsamplesize (options, Reqwidth, reqheight); Options.injustdecodebounds = 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 cursor= getcontentresolver (). Query (MediaStore.Images.Media.EXTERNAL_ Content_uri, NULL, NULL, NULL, or null);        while (Cursor.movetonext ()) {            String path = cursor.getstring (Cursor.getcolumnindex (Mediacolumns.data));            Paths.add (path);        }        Cursor.close ();    }
2. Custom adapter, load picture in adapter GetView method
    @Override public    View getView (int position, view Convertview, ViewGroup parent) {        Viewholder holder=null;        if (convertview==null) {            Convertview = Layoutinflater.from (This.mcontext). Inflate (R.layout.grid_item_layout, NULL);            Holder = new Viewholder ();            Holder.photo= (ImageView) Convertview.findviewbyid (R.id.photo);            Convertview.settag (holder);        } else{            holder= (viewholder) Convertview.gettag ();        }                Final String Path = this.paths.get (position);        Holder.photo.setImageBitmap (Imageloader.getbitmapfromcache (path));        return convertview;    }

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.

    Private Executorservice executor;        Private Imageloader (Context mcontxt) {super ();    Executor = Executors.newfixedthreadpool (3); }//Load image Async method, containing callback listener public void LoadImage (final ImageView view, Final String path, final int Reqwidth, Final int reqheight, final Onbitmaploadedlistener callback) {final Handler Mhandler = new Handler () {@Override public void Handlemessage (Message msg) {Super.ha                Ndlemessage (msg);                    Switch (msg.what) {case 1:bitmap Bitmap = (Bitmap) msg.obj;                    Callback.displayimage (view, bitmap);                Break                Default:break;                }            }                    }; Executor.execute (New Runnable () {@Override public void run () {Bitmap Bitmap = l Oadbitmapinbackground (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:

  In adapter:

        Holder.photo.setImageResource (r.drawable.ic_launcher);        Holder.photo.setTag (path);        Imageloader.loadimage (Holder.photo,                path,                 densityutil.dip2px,                densityutil.dip2px),                 new Onbitmaploadedlistener () {            @Override public            void DisplayImage (ImageView view, Bitmap Bitmap) {                String Imagepath= View.gettag (). toString ();                if (imagepath.equals (path)) {                    view.setimagebitmap (bitmap);}}        );

In Imageloader:

Executor.execute (New Runnable () {                @Override 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);                        Msg.obj = 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.

 
private Imageloader (Context mcontxt) {super ();        Executor = Executors.newfixedthreadpool (3);        One-eighth of the app as a picture cache Activitymanager am= (activitymanager) Mcontxt.getsystemservice (Context.activity_service);        int maxSize = Am.getmemoryclass () *1024*1024/8; Mcache = new lrucache<string, bitmap> (maxSize) {@Override protected int sizeOf (String key, Bit            Map value) {return value.getrowbytes () *value.getheight ();    }        };        }//Save picture to cache public void Putbitmapinmemey (String path,bitmap Bitmap) {if (path==null) return;        if (bitmap==null) return;        if (Getbitmapfromcache (path) ==null) {this.mCache.put (path, bitmap);    }} public Bitmap Getbitmapfromcache (String path) {return mcache.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.