Android load large graphics, multiple graphs and LRUCache cache details _android

Source: Internet
Author: User

We often use a lot of pictures when we write Android programs, and different pictures always have different shapes and sizes, but in most cases, these pictures are larger than the size we need for our programs. For example, most of the pictures displayed in the system picture library were taken with the mobile phone camera, and the resolution of these images is much higher than the resolution of our mobile screen. You should know that we write the application has a certain memory limit, the program occupies too much memory can easily appear oom (outofmemory) exception. We can see in the following code the maximum available memory for each application

int maxmemory = (int) (Runtime.getruntime (). MaxMemory ()/1024);
LOG.D ("TAG", "Max memory is" + MaxMemory + "KB");

So when you show high-resolution pictures, it's best to compress the pictures first. The size of the compressed picture should be similar to the size of the control used to display it, showing an oversized picture on a small imageview does not bring any visual benefit, but it takes up quite a lot of our valuable memory and can have a negative impact on performance. Let's take a look at how to compress a large picture properly so that it can be displayed at the best size while preventing Oom from appearing.

Bitmapfactory This class provides multiple parsing methods (Decodebytearray, DecodeFile, Decoderesource, etc.) for creating bitmap objects, we should choose the appropriate method based on the source of the image. For example, the image in SD card can use the DecodeFile method, the picture on the network can use the Decodestream method, the picture in the resource file can use Decoderesource method. These methods will attempt to allocate memory for the bitmap that have been built, and this can easily cause oom to appear. Each of these parsing methods provides an optional

Bitmapfactory.options parameter, setting the Injustdecodebounds property of this parameter to true allows the parsing method to prohibit allocating memory for bitmap, and the return value is no longer a bitmap object, but null. Although the bitmap is null, the Outwidth, Outheight, and Outmimetype properties of the bitmapfactory.options will be assigned. This technique allows us to get the long width and mime type of the picture before loading the picture to compress the picture according to the situation. As shown in the following code:

Bitmapfactory.options Options = new Bitmapfactory.options (); 
Options.injustdecodebounds = true; 
Bitmapfactory.decoderesource (Getresources (), r.id.myimage, options); 
int imageheight = options.outheight; 
int imagewidth = Options.outwidth; 

To avoid oom exceptions, it's a good idea to check the size of each picture first, unless you trust the source of the image to ensure that it doesn't exceed the available memory of your program.

Now that the size of the picture is known, we can decide whether to load the entire picture into memory or load a compressed version of the picture into memory. Here are a couple of factors that we need to consider:

    1. Estimate the memory required to load the entire picture
    2. In order to load this picture, how much memory would you like to provide
    3. The actual size of the control used to display this picture
    4. Screen size and resolution of the current device

For example, your ImageView only 128*96 pixel size, just to display a thumbnail, at this time, a picture of 1024*768 pixel completely loaded into memory is obviously not worth it

So how do we compress a picture? This can be achieved by setting the value of the insamplesize in the bitmapfactory.options. For example, we have a 2048*1536 pixel picture, the Insamplesize value is set to 4, you can compress this picture into 512*384 pixels. Originally loaded this picture needs to occupy 13M of memory, compressed only need to occupy 0.75M (assuming the picture is the argb_8888 type, that is, each pixel occupies 4 bytes). The following method calculates the appropriate insamplesize value according to the width and height of the incoming:

public static int Calculateinsamplesize (bitmapfactory.options Options, 
  int reqwidth, int reqheight) { 
 // The height and width of the source picture 
 final int height = options.outheight; 
 Final int width = options.outwidth; 
 int insamplesize = 1; 
 if (Height > reqheight | | | width > reqwidth) { 
  //Calculate the ratio of the actual width and height of the goal to the 
  final int heightratio = Math.Round ((float) Height/(float) reqheight); 
  Final int widthRatio = Math.Round ((float) width/(float) reqwidth); 
  Choose width and high school minimum ratio as the value of insamplesize, so that the final picture width and height 
  //must be greater than or equal to the width and height of the target. 
  insamplesize = HeightRatio < widthRatio? heightratio:widthratio; 
 } 
 return insamplesize; 
} 

Using this method, you first have to set the Bitmapfactory.options Injustdecodebounds property to True to parse the picture once. The bitmapfactory.options can then be passed along with the desired width and height to the Calculateinsamplesize method to get the appropriate insamplesize value. After parsing the picture again, using the newly acquired Insamplesize value and setting the Injustdecodebounds to False, you can get the compressed picture.

public static Bitmap Decodesampledbitmapfromresource (resources res, int resid, 
  int reqwidth, int reqheight) { 
 // The first resolution sets Injustdecodebounds to true to get the picture size 
 final bitmapfactory.options Options = new Bitmapfactory.options (); 
 Options.injustdecodebounds = true; 
 Bitmapfactory.decoderesource (res, resid, options); 
 Invoke the method defined above to compute the insamplesize value 
 options.insamplesize = calculateinsamplesize (options, Reqwidth, reqheight); 
 Resolves the picture Options.injustdecodebounds = False again using the obtained insamplesize value 
 ; 
 Return Bitmapfactory.decoderesource (res, resid, options); 
 

The following code simply compresses any picture into a 100*100 thumbnail and displays it on the ImageView

Mimageview.setimagebitmap (
Decodesampledbitmapfromresource (Getresources (), R.id.myimage, 100, 100));

LRUCache Cache

It's easy to load a picture in the UI interface of your application, but when you need to load a bunch of pictures on the interface, things get a lot more complicated. In many cases, (such as using ListView, GridView, or Viewpager), images displayed on the screen can be constantly increased by events such as sliding screens, resulting in oom

In order to ensure that the use of memory is always in a reasonable range, will often be removed from the screen of the image of the recovery process. The garbage collector will also assume that you are no longer holding references to these pictures, so that they can be GC-operated. This is a good way to solve the problem, but in order to allow the program to run quickly, in the interface to quickly load the picture, you have to consider some of the pictures are recycled, the user slipped it back into the screen. At this point again to load the picture just loaded is undoubtedly a performance bottleneck, you need to find ways to avoid this situation

At this point, using the memory caching technique is a good solution to this problem, and it allows components to quickly reload and process pictures. Let's take a look at how to use memory caching techniques to cache pictures so that your application can increase response speed and fluency when loading many pictures

Memory caching technology provides fast access to pictures that are heavily occupied with the valuable memory of an application. One of the most central classes is LRUCache (this class is provided in the ANDROID-SUPPORT-V4 package). This class is ideal for caching pictures, and its main algorithm is to store recently used objects in linkedhashmap with strong references, and to remove the least recently used object from memory before it reaches a preset value

In the past, we often used a very popular implementation of memory caching techniques, that is, soft references or weak references (SoftReference or weakreference). But this is no longer recommended because the garbage collector, starting with the Android 2.3 (API Level 9), is more likely to recycle objects that hold soft references or weak references, making soft references and weak references less reliable. In addition, in the Android 3.0 (API level 11), the image data is stored in local memory, so it cannot be released in a predictable way, which has the potential risk of an application memory overflow and crash

In order to be able to choose a suitable cache size for LRUCache, there are several factors that should be taken into consideration, such as:

    1. How much memory can your device allocate for each application?
    2. How many pictures can be displayed on the device screen at most once? How many pictures need to be preloaded because they are likely to be displayed on the screen soon?
    3. What is the screen size and resolution of your device, respectively? An ultra-high resolution device (such as the Galaxy Nexus) requires more cache space than a lower-resolution device (for example, Nexus S) when holding the same number of images
    4. The size and size of the picture, and how much memory space each picture will occupy
    5. How often are the pictures accessed? Will there be some pictures that are more frequently accessed than others? If so, you might want to have some images reside in memory, or use multiple LRUCache objects to distinguish pictures from different groups.
    6. Can you maintain a good balance between quantity and quality? Sometimes, it's more efficient to store multiple images with low pixels and to Chengga in the background to have high pixel-loaded images.

There is not a specified cache size that can satisfy all applications, and it is up to you to decide. You should analyze the usage of the program memory and work out a suitable solution. A too small cache space, which can cause pictures to be released and reloaded frequently, does not benefit. And a too large cache space, it is possible or will cause Java.lang.OutOfMemory of the exception

Example

Here is an example of using LruCache to cache a picture:

 private lrucache<string, bitmap> Mmemorycache; 
 @Override protected void OnCreate (Bundle savedinstancestate) {//Get the maximum amount of available memory, using memory beyond this value can cause a OutOfMemory exception. 
 LRUCache the cached value, in kilobytes, through the constructor. 
 int maxmemory = (int) (Runtime.getruntime (). MaxMemory ()/1024); 
 Use 1/8 of the maximum available memory value as the size of the cache. 
 int cacheSize = MAXMEMORY/8; Mmemorycache = new lrucache<string, bitmap> (cacheSize) {@Override protected int sizeOf (String key, Bitmap bit 
   MAP) {//Override this method to measure the size of each picture and return the number of pictures by default. 
  return Bitmap.getbytecount ()/1024; 
} 
 }; public void Addbitmaptomemorycache (String key, Bitmap Bitmap) {if (Getbitmapfrommemcache (key) = null) {Mmemory 
 Cache.put (key, bitmap); 
} public Bitmap Getbitmapfrommemcache (String key) {return mmemorycache.get (key); } 

In this example, the one-eighth memory allocated by the system to the application is used as the cache size. In the middle and high configuration of the mobile phone, this will probably have 4 megabytes (32/8) of cache space. A Full-screen GridView is populated with 4 800x480 resolution images, which will probably take up 1.5 trillion of space (800*480*4). Therefore, this cache size can store 2.5 of pages of pictures.

When a picture is loaded into the ImageView, it is first checked in the LruCache cache. If the corresponding key value is found, it will be more imageview immediately, otherwise open a background thread to load this picture

public void LoadBitmap (int resid, ImageView imageview) { 
 final String ImageKey = string.valueof (resid); 
 Final Bitmap Bitmap = Getbitmapfrommemcache (ImageKey); 
 if (bitmap!= null) { 
  imageview.setimagebitmap (bitmap); 
 } else { 
  Imageview.setimageresource ( R.drawable.image_placeholder); 
  Bitmapworkertask task = new Bitmapworkertask (ImageView); 
  Task.execute (RESID); 
 } 
 

Bitmapworkertask also puts the key-value pairs of the newly loaded picture into the cache

Class Bitmapworkertask extends Asynctask<integer, Void, bitmap> { 
 //loading pictures in the background. 
 @Override 
 protected Bitmap doinbackground (Integer ... params) { 
  final Bitmap Bitmap = Decodesampledbitmapfromresource ( 
    getresources (), Params[0], m; 
  Addbitmaptomemorycache (String.valueof (Params[0]), bitmap); 
  return bitmap 
 } 
} 

Master the above two methods, whether it is to load large pictures in the program, or to load a large number of pictures, do not have to worry about the oom problem! But it is only a theoretical introduction not to know that people can not fully understand.

Thank you for reading, I hope to help you, thank you for your support for this site!

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.