Android optimized picture optimization

Source: Internet
Author: User

1. Manipulate the picture itself

Try not to use Setimagebitmap, Setimageresource,
Bitmapfactory.decoderesource to set a large image, because these methods are finished decode, and eventually through the Java layer CreateBitmap to complete, need to consume more memory. Therefore, instead of using the Bitmapfactory.decodestream method first to create a bitmap, and then set it to ImageView Source,decodestream the biggest secret is its direct call jni>> Nativedecodeasset () to complete the decode, eliminating the need to use the Java layer CreateBitmap, thus saving the Java layer of space. If the Config parameter is added at the time of reading, it can more effectively reduce the loaded memory, thus more effectively prevent throwing memory exception. In addition, Decodestream directly take the picture to read the bytecode, not according to the machine's various resolutions to automatically adapt, after using the Decodestream, you need to configure the corresponding image resources in hdpi and mdpi,ldpi, Otherwise the same size (number of pixels) is the same on different resolution machines, and the displayed size is wrong.

inputstream is = This () .openrawresource  (R . drawable  .pic ) ;  Bitmapfactory options = new Bitmapfactory ()  Options.injustdecodebounds  = False;  Options.insamplesize  = 2   Bitmap BTP =bitmapfactory.decodestream  (is,null,options)   

The above code is read drawable under the name of the pic image thumbnail, length, width is only 1/2 of the original picture. The image size is reduced, and the memory used naturally becomes smaller. The disadvantage of this is that the picture quality is poor, the larger the value of the insamplesize, the picture quality is worse. Scaling pictures on different phones may be different depending on the algorithm used by each handset maker to scale pictures.

2. Read a picture of a local resource in the most memory-saving way
/** * Read pictures of local resources in the most memory-saving way */ Span class= "Hljs-keyword" >public  static  Bitmap  Readbitmap  (Context context, int  resId) {bitmapfactory.options opt = new  bitmapfactory.options ();     Opt.inpreferredconfig = Bitmap.Config.RGB_565;     opt.inpurgeable = true ;     opt.ininputshareable = true ;   //get the resource picture      InputStream is = Context.getresources (). Openrawresource (ResId); return   Bitmapfactory.decodestream (Is,null , opt); }

There are four color modes for loading images in Android: alpha_8:1byte per pixel, argb_4444:2byte memory per pixel, argb_8888:4byte memory per pixel, rgb_565: per pixel occupancy 2byte of memory. Android default color mode for argb_8888, this color mode color is the most delicate, showing the highest quality. But the same, the memory is also the largest. The above code reads the picture resource in rgb_565 (or argb_4444) mode. Memory reduction is not as obvious as the first method, but for most pictures, there is no difference between the argb_8888 pattern. However, when you read a picture with a gradient effect, a color bar may appear. In addition, it will affect the effect of the image processing.

3. How to change the color mode of a picture enlarged with the Matrix object:

While zooming in on a picture with a Matrix object will certainly consume more memory, but sometimes you have to. The enlarged image uses the argb_8888 color mode, even if the original picture is argb_4444 color mode, and there is no way to specify the color mode directly when zoomed in. You can change the picture color mode in the following ways.

matrix matrix = new  Matrix ();       Span class= "Hljs-keyword" >float  newwidth = 200 ; //image enlarged width       float  newheight = 300 ; //image enlarged length  Matrix.postscale (Newwidth/img.getwidth (), Newheight/img.getheight () ); Bitmap IMG1 = Bitmap.createbitmap (img, 0 , 0 , Img.getwidth (), Img.getheight (), Matrix, true ); //get enlarged picture  Img2 = Img1.copy (Bitmap.Config.ARGB_4444,                            False ); //get the picture of argb_4444 color mode  img = null ; img1 = null ;  

This creates an additional picture object IMG1 than the original image. But the system will actively accept the takeover img1, so the actual memory is still cut.

It boils down to reading pictures in thumbnail mode and cutting down on the memory used by each pixel in the picture most effectively. These two methods are effective, but also have their own shortcomings. The actual opening up or should be applied according to the scene as appropriate. The most benevolent way, or to avoid the generation of garbage objects. For example, in the application of the ListView, multiplexing Convertview and so on. If you apply asynctask to load a picture, set the referenced ImageView object to NULL in time. Because Asynctask is implemented with a thread pool, the objects referenced in this may have a very long life cycle, causing the GC to be unable to be acquitted. I still rely on Android memory accept takeover mechanism, recycle what is certainly the extent of effective, but always feel inappropriate Java memory accept takeover principle.

4. Compress the image

If your control size is smaller than the original picture size, you need to compress the picture to reduce memory usage.
Now that you know the size of the original picture, depending on the actual situation you want to load it down how many times after the picture. For example, if you use a 128x96 imageview to display a 1024x768 image, there is no need to load the original read into memory.
Load a reduced image into memory, just set the insamplesize of the Bitmapfactory.options object to True,
Then set a value for Insamplesize (you can understand that Insamplesize is N, the picture shrinks to 1/n size).

 Public StaticBitmapDecodesampledbitmapfromresource(Resources Res,intResId,intReqwidth,intReqheight) {//First decode with injustdecodebounds=true to check dimensions    FinalBitmapfactory.options Options =NewBitmapfactory.options (); Options.injustdecodebounds =true; Bitmapfactory.decoderesource (res, resId, options);//Calculate insamplesizeOptions.insamplesize = calculateinsamplesize (options, Reqwidth, reqheight);//Decode bitmap with Insamplesize setOptions.injustdecodebounds =false;returnBitmapfactory.decoderesource (res, resId, options); } Public Static int calculateinsamplesize(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; }
5. Using Memory Cache

For caching, no size or rule applies to all apps, it relies on you to determine your own scenarios by analyzing the memory usage of your app.
Cache too small may only add extra memory usage, cache too large may cause memory overflow or application other modules can use memory too small

PrivateLrucache<string, bitmap> Mmemorycache;@Overrideprotected void onCreate(Bundle savedinstancestate) {    ...//Get Max available VM memory, exceeding this amount would throw an    //OutOfMemory exception. Stored in kilobytes as LruCache takes an    //int in its constructor.    Final intMaxMemory = (int) (Runtime.getruntime (). MaxMemory ()/1024x768);//Use 1/8th of the available memory for this memory cache.    Final intCacheSize = maxmemory/8; Mmemorycache =NewLrucache<string, bitmap> (cacheSize) {@Override        protected int sizeOf(String key, Bitmap Bitmap) {//The cache size is measured in kilobytes rather than            //number of items.            returnBitmap.getbytecount ()/1024x768;    }    }; ...} Public void Addbitmaptomemorycache(String key, Bitmap Bitmap) {if(Getbitmapfrommemcache (key) = =NULL) {Mmemorycache.put (key, bitmap); }} PublicBitmapGetbitmapfrommemcache(String key) {returnMmemorycache.get (key);}

Load compressed picture to ImageView display

publicvoidloadBitmap(int resId, ImageView imageView) {    final String imageKey = String.valueOf(resId);    final Bitmap bitmap = getBitmapFromMemCache(imageKey);    ifnull) {        mImageView.setImageBitmap(bitmap);    else {        mImageView.setImageResource(R.drawable.image_placeholder);        new BitmapWorkerTask(mImageView);        task.execute(resId);    }}

Bitmapworkertask the picture is loaded, the image is also cached in memory:

class BitmapWorkerTask extends AsyncTask {      ...      in background.      @Override      protected Bitmap doInBackground(Integer... params) {          final Bitmap bitmap = decodeSampledBitmapFromResource(                  getResources(), params[0100100));          addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);          return bitmap;      }      ...  }  
6. Using Disk Caching

Your app can also be interrupted by other tasks, such as phone calls, where the app may end up in the background and the cached data will be lost.
When the user returns to the app, all the pictures need to be retrieved again.
Disk caching can be applied to this scenario, which reduces the number of times you get a picture, and of course, getting a picture from a disk is much slower than getting it from memory, so it needs to be done in a non-UI thread.
In the sample code is an implementation of the disk cache, in the Android4.0 source code (Libcore/luni/src/main/java/libcore/io/disklrucache.java),
There is a more powerful and recommended implementation, and its backwards compatibility makes it easy to use it in published libraries

Private Disklrucache mdiskcache;private static final int disk_cache_size =1024x768*1024x768*Ten; 10MBprivate static final String Disk_cache_subdir ="Thumbnails"; @Overrideprotected void OnCreate (Bundle savedinstancestate) {...Initialize Memory Cache...File Cachedir = Getcachedir (this, disk_cache_subdir); Mdiskcache = Disklrucache.opencache (this, Cachedir, disk_cache_size);...}class Bitmapworkertask extends Asynctask {...Decode imageinchBackground. @Override protected Bitmap doinbackground (Integer ... params) {final String ImageKey = string.valueof (params[0]); Check Disk CacheinchBackground thread Bitmap Bitmap = Getbitmapfromdiskcache (ImageKey);if(bitmap = = null) {//Not foundinchDisk Cache/Process as normal final Bitmap Bitmap = Decodesampledbitmapfromresource ( Getresources (), params[0], -, -)); }//ADD final bitmap to caches Addbitmaptocache (string.valueof (ImageKey, bitmap);returnBitmap }...}public void Addbitmaptocache (String key, Bitmap Bitmap) {//ADD to memory cache as beforeif(Getbitmapfrommemcache (key) = = NULL)    {Mmemorycache.put (key, bitmap); }//Also add to disk cacheif(!mdiskcache.containskey (key))    {Mdiskcache.put (key, bitmap); }}public Bitmap Getbitmapfromdiskcache (String key) {returnMdiskcache.get (key);} Creates a unique subdirectory of the designated app cache directory. Tries to use external//butifNot mounted, falls back on internal storage.public static File Getcachedir (context context, String UniqueName) {//Che CkifMedia is mounted or storage is built-inch,ifSoTryand use external cache dir//otherwise use internal cache dir final String CachePath = Environment.getexternalstora Gestate () = = Environment.media_mounted | | !                    Environment.isexternalstorageremovable ()? Context.getexternalcachedir (). GetPath (): Context.getcachedir (). GetPath ();returnNew File (CachePath + file.separator + uniqueName);}

Configuration changes at run time, such as the screen switching to a good user experience, you may not want to retrieve the picture again in this case.
Fortunately, you can use the memory cache described above. The cache can be uploaded to the new activity by using a fragment (call Setretaininstance (true),
When the new activity is created, just reattach the fragment, and you can get the fragment and access the existing cache to quickly display the images inside.

PrivateLruCache Mmemorycache;@Overrideprotected void onCreate(Bundle savedinstancestate)    {    ...    Retainfragment mretainfragment = retainfragment.findorcreateretainfragment (Getfragmentmanager ()); Mmemorycache = Retainfragment.mretainedcache;if(Mmemorycache = =NULL) {Mmemorycache =NewLruCache (cacheSize) {...//Initialize cache here as usual} Mretainfragment.mretainedcache = Mmemorycache; }    ...} Class Retainfragment extends Fragment {Private Static FinalString TAG ="Retainfragment"; PublicLruCache Mretainedcache; Public retainfragment() {} Public StaticRetainfragmentfindorcreateretainfragment(Fragmentmanager FM) {Retainfragment fragment = (retainfragment) fm.findfragmentbytag (TAG);if(Fragment = =NULL) {fragment =NewRetainfragment (); }returnFragment }@Override     Public void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setretaininstance (true); }}

Reference: Http://blog.csdn.net/yudajun/article/details/9323941#comments

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Android optimized picture optimization

Related Article

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.