Android high-load large graphics, multiple graphics solutions to effectively avoid program oom_android

Source: Internet
Author: User

The main content of this article from Android Doc, I translated and done some processing, English good friends can also directly read the original.
Http://developer.android.com/training/displaying-bitmaps/index.html

Load large pictures efficiently

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 how much memory is available 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 and prevent 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 that sets the Injustdecodebounds property of this parameter to true to prevent the parsing method from 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; 
String imagetype = Options.outmimetype; 

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. Some of the following factors are

We need to consider:

Estimate the amount of memory that is required to load the entire picture.
How much memory would you like to load in this picture?
The actual size of the control used to display this picture.
Screen size and resolution of the current device.

For example, your ImageView only 128*96 pixel size, just to show 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));

Using Picture caching techniques

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 the cached value reaches the 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 the application's 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:

How much memory can your device allocate for each application?

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?
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 (such as Nexus S) to hold the same number of images.

The size and size of the picture, and how much memory space each picture occupies.

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.

Can you maintain a good balance between quantity and quality? Sometimes it is more efficient to store multiple images with low pixels and to Chengga in the background to pick up images with high pixel loads.
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. A large cache space, however, can cause java.lang.OutOfMemory exceptions.

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 
      Bitmap) {//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) {MMe 
  Morycache.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 a imageview, it is first checked in the LruCache cache. If the corresponding key value is found, the ImageView is updated immediately or a background thread is turned on to load the picture.

 public void LoadBitmap (int resid, ImageView imageview) {final String ImageKey = Stri 
  Ng.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. 
  [Java] View plain copy class Bitmapworkertask extends Asynctask<integer, Void, bitmap> {//loading pictures in the background. @Override protected Bitmap doinbackground (Integer ... params) {final Bitmap Bitmap = Decodesampledbitmapfromresour 
    CE (getresources (), params[0], 100, 100); 
    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 worry about the oom problem! However, it is only a theoretical introduction do not know that you can not fully understand, in the following article I will demonstrate how to use these techniques flexibly in the actual program to avoid the program Oom, Interested friends please continue to read the Android photo wall application implementation, no amount of pictures are not afraid to crash.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.