Android Bitmap Cache Pool Usage detailed _android

Source: Internet
Author: User

This article describes how to use caching to improve the flow of load input and sliding for the UI. Using memory caching, using disk caching, handling configuration change events, and so on, will solve this problem effectively.

Displaying a single picture in your UI is very simple, and it's a bit more complicated if you need to show a lot of pictures at once. In many cases (such as using ListView, GridView, or Viewpager controls), pictures displayed on the screen and the number of pictures that will be displayed on the screen are very large (for example, browsing a large number of pictures in a gallery).

In these controls, when a child control is not displayed, the control is reused to loop the display in order to reduce memory consumption. The garbage collection mechanism also frees bitmap resources that are already loaded in memory (assuming you do not have strong references to these bitmap). This is generally good, but you need to avoid duplicating the images that need to be displayed in order to keep the UI flowing and to load the image efficiently when the user slides back and forth on the screen. Using memory caching and disk caching can solve this problem, and caching allows the control to quickly load a picture that has already been processed.

This article describes how to use caching to improve the flow of load input and sliding for the UI.

Using the memory cache

The memory cache increases the speed of access to the picture, but consumes a lot of memory. LruCache
Class (You can use the classes in the support Library before API 4) is especially good for caching bitmap, putting the most recently used
The bitmap object is saved with a strong reference (saved to the Linkedhashmap), and when the amount of cache reaches a predetermined value, the
Objects that are infrequently used are deleted.

Note: in the past, the common practice for implementing memory caching is to use the
SoftReference or
WeakReference Bitmap Cache,
However, this approach is not recommended. Starting with the Android 2.3 (API level 9), garbage collection begins to force the recycling of soft/weak references, causing these caches to have no efficiency gains.
In addition, these cached bitmap data are stored in the underlying memory (native memory) before the Android 3.0 (API level 11), and they are not released when they are reached, which can cause
The program exceeded the memory limit and crashed.

When using LruCache, you need to consider the following factors to select an appropriate number of cache parameters:

1. How much memory is available in the program
2. How many pictures are displayed on the screen at the same time? How many pictures do you want to cache first to display on the screen you're about to see?
3. What is the screen size and screen density of the equipment? Ultra high screen density (xhdpi such as Galaxy Nexus)
4. Devices that display the same picture require more memory than low screen density (hdpi such as Nexus S) devices.
5. The size and format of the picture determine how much memory each picture needs to occupy
6. How often is the picture accessed? How often do some pictures have more access than other pictures? If so, you may want to put these frequently accessed pictures into memory.
7. What is the balance between quality and quantity? In some cases, it is useful to save a large number of low-quality pictures, and use the background thread to add a high-quality version of the picture when needed.

There is no one-size-Fits-all formula available for all programs, you need to analyze your usage and specify your own caching strategy. Using too small a cache does not work as expected, and using too much cache consumes more
Memory may cause java.lang.OutOfMemory anomalies or leave little memory for use by other functions of your program.

The following is an example of using the LruCache cache:

Copy Code code as follows:

Private lrucache<string, bitmap= "" > Mmemorycache;

@Override
protected void OnCreate (Bundle savedinstancestate) {
...
Get memory class of this device, exceeding this amount'll throw an
OutOfMemory exception.
Final int memclass = ((Activitymanager) Context.getsystemservice (
Context.activity_service)). Getmemoryclass ();

Use 1/8th of the the available memory for this memory cache.
Final int cacheSize = 1024 * 1024 * MEMCLASS/8;

Mmemorycache = new lrucache<string, bitmap= "" > (cacheSize) {
@Override
protected int sizeOf (String key, Bitmap Bitmap) {
The cache size is measured in bytes rather than number of items.
return Bitmap.getbytecount ();
}
};
...
}
public void Addbitmaptomemorycache (String key, Bitmap Bitmap) {
if (Getbitmapfrommemcache (key) = null) {
Mmemorycache.put (key, bitmap);
}
}
Public Bitmap Getbitmapfrommemcache (String key) {
return Mmemorycache.get (key);
}


Note:In this example, 1/8 of the program's memory is used for caching purposes. In a normal/hdpi device, this has at least 4MB (32/8) of memory.
In a device with a resolution of 800x480, the full screen of the GridView full fill picture will be used almost 1.5MB (800*480*4 bytes)
Memory, so it's almost 2.5-page images cached in memory.

When you display a picture in ImageView,
Check the presence of the LRUCache first. If it exists, use the cached picture, and if it does not exist, start the background thread to load the picture and cache it:

Copy Code code as follows:

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

Bitmapworkertask need to add new pictures to the cache:
Copy Code code as follows:

Class Bitmapworkertask extends Asynctask<integer, void,= "bitmap=" "> {
...
Decode image in background.
@Override
Protected Bitmap doinbackground (Integer ... params) {
Final Bitmap Bitmap = Decodesampledbitmapfromresource (
Getresources (), params[0], 100, 100);
Addbitmaptomemorycache (String.valueof (Params[0]), bitmap);
return bitmap;
}
...
}

The next page will introduce you to the other two ways of using disk caching and handling configuration change events

Using Disk caching

The memory cache is fast in accessing recently used pictures, but you cannot determine if the picture exists in the cache. Like
GridView This control may have many pictures to display, and soon the picture data fills up the cache capacity.
Your program may also be interrupted by other tasks, such as incoming calls-when your program is in the background, the system may be aware of these image caches. Once the user resumes using your program, you will also need to process the pictures again.

In this case, you can use disk caching to hold these processed pictures, which can be loaded from the disk cache when they are not available in the memory cache, omitting the image processing process.
Of course, loading a picture from disk is a lot slower than reading from memory, and you should load a disk picture in a non-UI thread.

Note: If the cached pictures are used frequently, you may consider using the
ContentProvider, for example, is the case in the gallery program.

There is a simple disklrucache implementation in the sample code. Then, the Android 4.0 contains a more reliable and recommended Disklrucache (Libcore/luni/src/main/java/libcore/io/disklrucache.java)
。 You can easily migrate this implementation to the previous version of 4.0 (to href= "Http://www.google.com/search?q=disklrucache" >google to see if others have done this!). )。

Here is an updated version of Disklrucache:

Copy Code code as follows:

Private Disklrucache Mdiskcache;
private static final int disk_cache_size = 1024 * 1024 * 10; 10MB
private static final String Disk_cache_subdir = "thumbnails";

@Override
protected 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<integer, void,= "bitmap=" > {
    ...
   //Decode image in background.
    @Override
    protected Bitmap doinbackground (Integer ... params) {
  ;       final String ImageKey = string.valueof (params[0]);

       //Check disk cache in background thread
    & nbsp;   Bitmap Bitmap = Getbitmapfromdiskcache (ImageKey);

if (bitmap = null) {//not found in disk cache
Process as normal
Final Bitmap Bitmap = Decodesampledbitmapfromresource (
Getresources (), params[0], 100, 100);
}
ADD final bitmap to caches
Addbitmaptocache (string.valueof (ImageKey, bitmap);

return bitmap;
}
...
}
public void Addbitmaptocache (String key, Bitmap Bitmap) {
ADD to memory cache as before
if (Getbitmapfrommemcache (key) = null) {
Mmemorycache.put (key, bitmap);
}
Also Add to disk cache
if (!mdiskcache.containskey (key)) {
Mdiskcache.put (key, bitmap);
}
}
Public Bitmap Getbitmapfromdiskcache (String key) {
return Mdiskcache.get (key);
}
Creates a unique subdirectory of the designated app cache directory. Tries to use external
But if not mounted, falls back on internal storage.
public static File Getcachedir (context context, String UniqueName) {
Check If media is mounted or storage are built-in, if so, try and use external cache dir
Otherwise use internal cache dir
Final String CachePath = environment.getexternalstoragestate () = = environment.media_mounted
|| ! Environment.isexternalstorageremovable ()?
Context.getexternalcachedir (). GetPath (): Context.getcachedir (). GetPath ();
return new File (CachePath + file.separator + uniquename);
}


Detects the memory cache in the UI thread and detects the disk cache in the background thread. Disk operations should never be implemented in the UI thread. When the image is processed, the final result is added to the
The memory cache and the disk cache for future use.

Handling Configuration Change Events

Runtime configuration changes-such as screen orientation changes-cause Android to destroy the running activity and then use
The new configuration restarts the activity (for more information, refer here to handling Runtime Changes).
You need to be aware that you can improve the user experience by avoiding the process of reprocessing all the pictures when configuration changes occur.

Luckily, you already have a good picture cache in the memory cache section. The cache can be passed
Fragment (Fragment will be saved by the setretaininstance (true) function) to be passed to the new activity
When the activity restarts, Fragment is reattached to the activity, and you can get the cached object through the Fragment.

The following is an example of saving a cache in fragment:

Copy Code code as follows:

Private lrucache<string, bitmap= "" > Mmemorycache;
@Override
protected void OnCreate (Bundle savedinstancestate) {
...
Retainfragment mretainfragment = retainfragment.findorcreateretainfragment (Getfragmentmanager ());
Mmemorycache = Retainfragment.mretainedcache;
if (Mmemorycache = = null) {
Mmemorycache = new lrucache<string, bitmap= "" > (cacheSize) {
..///Initialize cache here as usual
}
Mretainfragment.mretainedcache = Mmemorycache;
}
...
}
Class Retainfragment extends Fragment {
private static final String TAG = "Retainfragment";
Public lrucache<string, bitmap= "" > Mretainedcache;

Public retainfragment () {}
public static retainfragment Findorcreateretainfragment (Fragmentmanager FM) {
Retainfragment fragment = (retainfragment) fm.findfragmentbytag (TAG);
if (fragment = = null) {
fragment = new Retainfragment ();
}
return fragment;
}
@Override
public void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
<strong>setretaininstance (True);</strong>
}
}


In addition, you can try to use and not use fragment to rotate the device's screen orientation to see the specific picture load.

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.