Android bitmap cache strategy, understand these, and come to Alibaba directly


How to avoid consuming too much traffic? When the program loads a picture from the network for the first time, it caches it on the mobile device, so that when the picture is used again, it does not need to download it from the network again, saving traffic for users.

At present, a commonly used cache algorithm is lru (least recently used). Its core idea is that when the cache is full, it will give priority to the cache objects that are least used in the near future. There are two kinds of caches using lru algorithm: lrucache and diskrucache. Lrucache is mainly used for memory cache, and diskrucache is used for storage device cache.

###1.lrucache
Lrucache is a generic class provided by api level 12. It uses a linkedhashmap to store external cache objects by strong reference, and provides get and put methods to complete cache acquisition and addition. When the cache is full, lrucache will remove the cache objects used earlier, and then add new objects.

In the past, softreference or weakreference was commonly used to implement memory cache, but this is not recommended. After api level 9, gc forcibly recycles soft and weak references, resulting in no efficiency improvement of these caches.
Implementation principle of lrucache:

According to lru's algorithm idea, we need a data structure to quickly locate which object is recently accessed and which object is not accessed for the longest time. lru cache selects the data structure linkedhashmap, which is a two-way circular linked list. Take a look at the linkedhashmap constructor:

/** Initialize linkedhashmap

     * First parameter: initialcapacity, initial size

     * The second parameter: loadfactor = 0.75f

     * The third parameter: accessorder=true, based on the access order; accessorder=false, based on the insertion order < br / >**/

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

       super(initialcapacity, loadfactor);

       init();

       this.accessorder = accessorder;

    }

Therefore, accessor = true should be selected in lrucache. When we call put and get methods, linkedhashmap will move this item to the tail of the linked list, that is, the item just used recently is at the tail of the linked list, and the item least used recently is at the head of the linked list. When the cache space is insufficient, you can remove the header node to free the cache space.
The following is an example of the typical usage posture of 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/>// Add a cache object to lrucache

private void addbitmaptomemorycache(string key, bitmap bitmap) {

    if (getbitmapfrommemcache(key) == null) {

        mmemorycache.put(key, bitmap);

    }

}



//Get a cache object

private bitmap getbitmapfrommemcache(string key) {

    return mmemorycache.get(key);

}</string>

In the above example code, the total capacity is one eighth of the available memory of the current process (the official recommendation is one eighth, ha, you can decide by yourself). The sizeof () method calculates the size of the bitmap. The sizeof method returns the number of item s you cache by default. return 1 directly in the source code (the source code here is relatively simple, you can see ~).

If you need to release a value in the cache, You can override the entryremoved () method, which will be called when the element is put or removed. The source code is empty by default. Rewriting the entryremoved () method can also implement the L2 memory cache to further improve the performance. The idea is as follows: Rewrite entryremoved (), store the deleted item s in another linkedhashmap. This data structure is used as a secondary cache. Each time you get an image, look it up in the order of primary cache, secondary cache, sdcard and network, and stop when you find it.

###2.disklrucache
When we need to save a large number of pictures, the cache space we specified may soon run out. lrucache will frequently perform trimtosize operations to remove the least recently used data. However, if the hold fails, we will use the data again and download it from the network. Therefore, with diskrucache, it can save these downloaded pictures. Of course, reading pictures from disk is much slower than memory, and disk pictures should be loaded in non ui threads. Diskrucache, as its name suggests, implements storage device cache, that is, disk cache. It realizes the cache effect by writing cache objects to the file system.

ps: if cached pictures are often used, consider using content provider.
Implementation principle of diskrucache:
lrucache uses a data structure like linkedhashmap to store objects in the cache. What about diskrucache? Because the data is cached in the local file, it is equivalent to a file that is persisted. Even if app kill is lost, these files are still dripping. so, what is it? Diskrucache also adopts the data structure of linekedhashmap, but it is not enough. It needs to support buff

Log file. The log file can be regarded as a "memory". The value in the map only saves the brief information of the file, and all operations on the cache file will be recorded in the log file.

Initialization of diskrucache:

The following is the creation process of diskrucache:

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();

        }

    }

Took a look, You can see the point () function, in which the first parameter represents the storage path of the file. The cache path can be the cache directory on the sd card, specifically / sdcard/android/data/package_name/cache. Package_name represents the package name of the current application. After the application is unloaded, this directory will be deleted. If you want these cache files not to be deleted after the application is unloaded, you can specify the sd card Other directories on. The second parameter indicates the version number of the application, which is generally set to 1. The third parameter indicates the number of data corresponding to a single node, which is generally set to 1. The fourth parameter indicates the total size of the cache, such as 50mb. When the cache size exceeds the set value, diskrucache will clear some caches to ensure that the total size will not exceed the set value
Data cache and fetch cache of diskrucache:
The data cache operation is performed with the help of diskrucache Completed by the editor class, editor represents the editing object of 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 encrypts the url, mainly to obtain a unified 16 bit character

            disklrucache.editor editor = mdisklrucache.edit(key);  //Get the editor and write the dirty record to the journal log

            if (editor != null) {  

                outputstream outputstream = editor.newoutputstream(0);  

                if (downloadurltostream(imageurl, outputstream)) {  //The downloadurltostream method is the method of downloading pictures, and the output stream is put into the outputstream

                    editor.commit();  //Remember to commit() after completion, and then write the clean record to the journal log
am)) {  //The downloadurltostream method is the method of downloading pictures, and the output stream is put into the outputstream

                    editor.commit();  //Remember to commit() after completion, and then write the clean record to the journal log
 

Keywords: Android Design Pattern data structure Cache

Added by redmonkey on Fri, 17 Dec 2021 19:51:33 +0200