android bitmap caching policy

In this article:

  • 1.lrucache
  • 2.disklrucache
  • 3. The cache policy comparison and summary

Whether android or ios device, the flow rate for the user is precious. In the absence of wifi scenario, if you load a batch of pictures consume too much user traffic, be it known, have to be talking about the wave ~

Here Insert Picture Description

How to avoid consuming too much traffic it? When the program first loads images from the network, it will be cached on the mobile device, so use this image again, do not download again from the network to the user to save traffic.

A commonly used caching algorithm is lru (least recently used), its core idea is that when the cache is full, will give priority to phase out the least recently used cache objects. Lru cache algorithm uses two: lrucache and disklrucache, lrucache mainly used for cache memory, disklrucache the storage device for the cache.

1.lrucache

lrucache is a generic class api level 12 provided within it to adopt a linkedhashmap stored outside of a strong reference to the cached object provides methods to get and put the completion of the acquisition and add cache operation, when the cache is full, will lrucache remove off the cache object used earlier, and then add a new object.

Over the past common practice is to use a memory cache to achieve softreference or use weakreference, but it is not recommended, From api level 9, gc mandatory recycling out soft, weak references, leading to the cache and did not improve any efficiency.

The principle of lrucache:
According to the idea lru algorithm, we need to quickly locate a data structure which is the object of a recent visit, which object is the longest without access, lrucache choice is linkedhashmap this data structure, it is a two-way circular list. To take a look at the constructor of a linkedhashmap:

/** 初始化linkedhashmap

     * 第一个参数:initialcapacity,初始大小

     * 第二个参数:loadfactor,负载因子=0.75f

     * 第三个参数:accessorder=true,基于访问顺序;accessorder=false,基于插入顺序<br/>**/

   public linkedhashmap(int initialcapacity, float loadfactor, boolean accessorder) {

       super(initialcapacity, loadfactor);

       init();

       this.accessorder = accessorder;

    }

So lrucache should choose accessorder = true, when we call the put, when the get method, linkedhashmap inside will move this item to the end of the list, which is in the tail of the list item recently used, the head of the list is the least recently used item. When the cache space is insufficient, you can remove the head node release buffer space.
The following are examples of typical usage posture lrucache:

int maxmemory = (int) (runtime.getruntime().maxmemory() / 1024);

int cachesize = maxmemory / 8;

mmemorycache = new lrucache<string bitmap="">(cachesize) {

    @override

    protected int sizeof(string key, bitmap bitmap) {

        return bitmap.getrowbytes() * bitmap.getheight() / 1024;

    }

};

 <br/>// 向 lrucache 中添加一个缓存对象

private void addbitmaptomemorycache(string key, bitmap bitmap) {

    if (getbitmapfrommemcache(key) == null) {

        mmemorycache.put(key, bitmap);

    }

}



//获取一个缓存对象

private bitmap getbitmapfrommemcache(string key) {

    return mmemorycache.get(key);

}</string>

The sample code above, the size of the total available memory capacity is one-eighth of the current process (official recommendation is one-eighth of Kazakhstan, you can set depending on their circumstances), sizeof () method to calculate the size of the bitmap, sizeof method the default is that you return the number of cached item, the source code directly return 1 (source here is relatively simple, you can look at yourself ~).

If you need a value to release the cache, you can override entryremoved () method, this method when the elements are put or remove call, the source code is empty by default to achieve. Rewriting entryremoved () method may also be implemented two cache memory, to further improve performance. Ideas are as follows: rewrite entryremoved (), to delete the item, again into another linkedhashmap in. This data structure as a second-level cache, each time you get the picture, according to a cache, the order of secondary cache, sdcard, network lookup and find stops.

2.disklrucache

When we need to save a large number of images, we specify the buffer space may soon run out, lrucache will be trimtosize operation frequently will remove the least recently used data out, but could not hold it too will have to use this data, and download it again from the network, for which has disklrucache, it can save these images have been downloaded. Of course, memory is much slower than reading from a disk image when the disk and should load images in non-ui thread. disklrucache name implies, to achieve cache storage device, i.e. a disk cache, cache it in order to achieve the effect of the cache written to the file system objects.

ps: If the cached images are often used, consider using contentprovider.

disklrucache implementation principle:

lrucache uses linkedhashmap this data structure to store objects in the cache, then for disklrucache it? Since the data is cached in the local paper, the equivalent of a persistent file, even if app kill off, these files are still dropping. so, in the end is what? disklrucache linekedhashmap also uses this data structure, but not enough, need the blessing buff

The log file. The log file can be seen as a "memory", map the value saved only brief information about the file, all operations will cache file is recorded in the log file.

disklrucache initialization:

Here is the process of creating disklrucache:

private static final long disk_cache_size = 1024 * 1024 * 50; //50mb 

    

    file diskcachedir = getdiskcachedir(mcontext, "bitmap");

    if (!diskcachedir.exists()) {

        diskcachedir.mkdirs();

    }



    if (getusablespace(diskcachedir) > disk_cache_size) {

        try {

            mdisklrucache = disklrucache.open(diskcachedir, 1, 1,

                    disk_cache_size);

        } catch (ioexception e) {

            e.printstacktrace();

        }

    }

Glanced know emphasis on open () function, wherein the first parameter represents a file storage path, the path may be cached on the cache directory sd card, specifically refers to / sdcard / android / data / package_name / cache, package_name represents the package name of the current application, when the application is uninstalled, this directory will be deleted out. If you want to uninstall the application, these cache files are not deleted, you can specify another directory on the sd card. The second parameter indicates the version number of the application, and generally can be set to 1. The third parameter is the number of data corresponding to a single node, usually set to 1. The fourth parameter represents the total size of the cache, such as 50mb, when the cache size exceeds this setting, disklrucache will clear some cache to ensure that the total size does not exceed the set value

disklrucache cache data buffers and access:
the data cache operation is completed by disklrucache.editor class, editor to edit the object represents a cache object.

new thread(new runnable() {  

    @override  

    public void run() {  

        try {  

            string imageurl = "http://d.url.cn/myapp/qq_desk/friendprofile_def_cover_001.png";  

            string key = hashkeyfordisk(imageurl);  //md5对url进行加密,这个主要是为了获得统一的16位字符

            disklrucache.editor editor = mdisklrucache.edit(key);  //拿到editor,往journal日志中写入dirty记录

            if (editor != null) {  

                outputstream outputstream = editor.newoutputstream(0);  

                if (downloadurltostream(imageurl, outputstream)) {  //downloadurltostream方法为下载图片的方法,并且将输出流放到outputstream

                    editor.commit();  //完成后记得commit(),成功后,再往journal日志中写入clean记录

                } else {  

                    editor.abort();  //失败后,要remove缓存文件,往journal文件中写入remove记录

                }  

            }  

            mdisklrucache.flush();  //将缓存操作同步到journal日志文件,不一定要在这里就调用

        } catch (ioexception e) {  

            e.printstacktrace();  

        }  

    }  

}).start();

When the above-described exemplary code, each call to edit () method returns a new editor objects, a file output stream can be obtained by it; calling commit () method writes the image to the file system, and if that fails, abort by () method rollback.

Acquiring process to be cached and the like is added to convert url to key, then get a snapshot of the object via the get method disklrucache, then cache file input stream obtained by the snapshot object. With the file input stream, bitmap to get to.

bitmap bitmap = null;

    string key = hashkeyformurl(url);

    disklrucache.snapshot snapshot = mdisklrucache.get(key);

    if (snapshot != null) {

        fileinputstream fileinputstream = (fileinputstream)snapshot.getinputstream(disk_cache_index);

        filedescriptor filedescriptor = fileinputstream.getfd();

        bitmap = mimageresizer.decodesampledbitmapfromfiledescriptor(filedescriptor,

                reqwidth, reqheight);

        ......

    }

disklrucache optimization thinking:

disklrucache is based on log files, cache files for each logging operations require, we can not log file, in the first structure disklrucache, access files in the cache directory directly from the program, and each cache file access time value as an initial value in the value recorded in the map, each access or storing buffer is updated corresponding key corresponding to the access time of the cache file, to avoid the frequent operation io.

3. The cache policy comparison and summary

  • lrucache is already packaged android type, disklrucache need to import only the corresponding packet can be used.
  • Ui thread can be used in direct lrucache; use disklrucache, because the cache or acquisition need to be operating on a local file, so to achieve in the sub-thread.
  • lrucache mainly used for cache memory, when the app kill off, the cache is immediately gone; and when disklrucache mainly used for cache storage device, app kill off, the cache is still
  • Lrucache internal implementation is linkedhashmap, or additional element for pick-put, get to the method. Disklrucache is cached by the form file stream, so the additional element is achieved by obtaining the input or output streams.

The article is written in a hurry, if there are typos or wrong understanding, welcome and thank the landlord exchange ~

Guess you like

Origin blog.csdn.net/Android_SE/article/details/90755330