美文网首页
Android 图片三级缓存 _内存缓存LruCache

Android 图片三级缓存 _内存缓存LruCache

作者: 信仰年輕 | 来源:发表于2021-03-25 15:34 被阅读0次

    本文目标

    理解Android图片三级缓存机制,并重点理解内存缓存 (LruCache算法)

    图片的缓存技术分为三级

    1.内存缓存 : 读取速度最快
    技术: LruCache(包含在SDK中)

    2.本地缓存 : 读取速度低于内存缓存
    技术: DiskLruCache(不包含在SDK中)

    2.网络缓存 : 读取速度最慢
    技术: 保存在服务器中

    图片的缓存流程:
    1.图片需要从缓存中获取的时候,先从内存缓存中获取,
    2.如果内存缓存没有的话,再从本地缓存中获取,如果在本地缓存中获取了则:添加到内存缓存中,并从本地缓存中移除,
    3.如果本地缓存中还没有的话,就只能从网络中去获取,从网络中拿到后分别更新内存缓存和本地缓存。

    内存缓存:LruCache

    缓存策略一般包括缓存的添加、获取、删除。缓存的添加和获取很容易懂,为什么要删除呢?无论是内存缓存还是硬盘缓存,缓存大小都是有限的,如果缓存满了,想要加进新的缓存,就需要删除一部分缓存,添加新的缓存。

    LruCache:Least rencently used 顾名思义:近期最少使用算法。LruCache和DisLruCache两个类,分别用于内存和硬盘缓存。核心思想是当缓存空间满了之后,会删除最近最少使用的缓存。

    LruCache是Android3.1实现的缓存类,所以android可以直接使用它来实现内存缓存。DisLruCache不是SDK中的一部分。

    1.LruCache的使用

    LruCache的原理是将缓存对象作为强引用,保存在LinkedHashMap中,当缓存满了之后,将对象从Map中移除,重新通过put方法添加新的缓存,get方法获取缓存。
    图片缓存为例

    int maxMemory = (int) (Runtime.getRuntime().totalMemory()/1024);
    int cacheSize = maxMemory/8;
    LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(cacheSize) {
            // 计算当前的Bitmap的内存大小,默认是返回 1。
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount() / 1024;
            }
    };
    

    1、设置LruCache缓存的大小,一般为当前进程可用的1/8。
    2、重写sizeOf方法,计算出缓存每张图片的大小

    2.LruCache的原理

    LruCache的核心思想就是维护一个缓存对象的队列,该队列由LinkedHashMap维护。一直没访问的对象放在队尾,最新访问的放在队首,当队列满了之后,从队尾开始淘汰,队首的最后淘汰。
    LruCache的源码里运用了LinkedHashMap的存取实现了缓存的添加(put)和获取(get)。

    put()方法

        public final V put(K key, V value) {
             //不可为空,否则抛出异常
            if (key == null || value == null) {
                throw new NullPointerException("key == null || value == null");
            }
    
            V previous;
            synchronized (this) {
                //插入的缓存对象值加1 
                putCount++;
                 //增加已有缓存的大小
                size += safeSizeOf(key, value);
                 //向map中加入缓存对象 
                previous = map.put(key, value);
                 //如果已有缓存对象,则缓存大小恢复到之前
                if (previous != null) {
                    size -= safeSizeOf(key, previous);
                }
            }
    
            if (previous != null) {
                //entryRemoved()是个空方法,可以自行实现
                entryRemoved(false, key, previous, value);
            }
             //调整缓存大小(关键方法)
            trimToSize(maxSize);
            return previous;
        }
    

    从代码可以看出,在添加缓存之后,调用了trimToSize方法,判断缓存是否已满,来判断缓存是否已满,如果满了就运用LruCache算法,删除队尾的缓存。

    private void trimToSize(int maxSize) {
            //死循环
            while (true) {
                K key;
                V value;
                synchronized (this) {
                     //如果map为空并且缓存size不等于0或者缓存size小于0,抛出异常
                    if (size < 0 || (map.isEmpty() && size != 0)) {
                        throw new IllegalStateException(getClass().getName()
                                + ".sizeOf() is reporting inconsistent results!");
                    }
                     //如果缓存大小size小于最大缓存,不需要再删除缓存对象,跳出循环
                    if (size <= maxSize) {
                        break;
                    }
    
                    //迭代器获取最后一个对象,即队尾的元素,近期最少访问的元素
                    Map.Entry<K, V> toEvict = null;
                    for (Map.Entry<K, V> entry : map.entrySet()) {
                        toEvict = entry;
                    }
                
                    if (toEvict == null) {
                        break;
                    }
    
                    key = toEvict.getKey();
                    value = toEvict.getValue();
                    //删除该对象,并更新缓存大小 
                    map.remove(key);
                    size -= safeSizeOf(key, value);
                    evictionCount++;
                }
    
                entryRemoved(true, key, value, null);
            }
        }
    

    总结

    LruCache只要就是维护了一个LinkedHashMap。当调用put方法时,向队列中加入缓存对象,然后调用trimToSize()判断缓存时候已满,如果满了,用LinkedHashMap的迭代器从队尾移除最近使用最少的缓存。获取缓存时调用get(),调用 LinkedHashMap的get方法,并将获取的数据更新到队首。

    相关文章

      网友评论

          本文标题:Android 图片三级缓存 _内存缓存LruCache

          本文链接:https://www.haomeiwen.com/subject/tqvvcltx.html