精华内容
下载资源
问答
  • lua-resty-lrucache-基于LuaJIT FFI的Lua-land LRU缓存。 目录 安装 社区 英文邮件列表 中文邮件列表 错误和补丁 作者 版权和许可 也可以看看 地位 该库被认为可以投入生产。 概要 -- file myapp.lua: example ...
  • LruCache 源码

    2020-11-05 15:22:01
    LruCache 源码,摘抄下来,方便查阅。 https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/util/LruCache.java
  • LruCache 什么是LruCacheLruCache实现原理是什么? 这两个问题其实可以作为一个问题来回答,知道了什么是 LruCache,就只然而然的知道 LruCache 的实现原理;Lru的全称是Least Recently Used ,近期最少使用的!...
  • 自定义实现LRUCache的实现和调用. 简单地扩展LinkedHashMap
  • 主要介绍了Android 加载大图、多图和LruCache缓存详细介绍的相关资料,需要的朋友可以参考下
  • lua-resty-lrucache, 在 LuaJIT FFI上,基于Lua缓存 电子邮件名称lua-resty-lrucache - 基于 LuaJIT FFI的land缓存目录NAME状态概要说明描述方法新插件设置 。删除先决条件安装工具待办事项社区服务英文邮件列表中文...
  • LRUCache内部使用LinkedHashMap来存储key-value键值对,并将LinkedHashMap设置为访问顺序来体现LRU算法。 无论是对某个key的get,还是set都算做是对该key的一次使用。当set一个不存在的key,并且LRU Cache中key的...
  • LRUCache

    2018-11-07 01:46:00
    请简述LRUcache原理,及常见应用场景。使用常用的java数据结构实现。 LRU(Least Recently Used)缓存算法是近期最少使用算法,其核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。主要算法原理是把最近...

    请简述LRUcache原理,及常见应用场景。使用常用的java数据结构实现。

    LRU(Least Recently Used)缓存算法是近期最少使用算法,其核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。主要算法原理是把最近使用的对象强引用存储在LinkedHashMap中,当缓存满时,把最近最少使用的对象从内存中移除,并提供了get和put方法来完成缓存的获取和添加操作。

    1、LRU的LinkedHashMap同步锁实现

    package com.boomoom.service.localDataMap
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    public class LRUCache<K, V> {
        private static final float hashLoadFactory = 0.75f;
        private LinkedHashMap<K, V> map;
        private int cacheSize;
    
        public LRUCache(int cacheSize) {
         this.cacheSize = cacheSize;
            int capacity = (int)Math.ceil(cacheSize / hashLoadFactory) + 1;
            map = new LinkedHashMap<K, V>(capacity, hashLoadFactory, true) {
                private static final long serialVersionID = 1;
    
                @Override
                protected boolean removeEldestEntry(Map.Entry eldest) {
                    return size() > LRUCache.this.cacheSize;
                }
            };
        }
    
        public V get(K key) {
            sychronized(this) {
                return map.get(key);
            }
        }
    
        public void put(K key, V value) {
            sychronized(this) {
                map.put(key, value);
            }
        }
    
        public void remove(Object key) {
            sychronized(this) {
                map.remove(key);
            }
        }
    
        public void clear() {
            sychronized(this) {
                map.clear();
            }
        }
    }

    2、LRU的LinkedHashMap读写锁实现

    package com.boomoom.service.localDataMap
    import java.util.LinkedHashMap;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class LruCache<K, V> {
        private int MAX_LENGTH = 1 << 30;  //最大长度
        private LinkedHashMap<K, V> map;
        private ReadWriteLock lock = new ReentrantReadWriteLock(); //读写锁
    
        public LruCache(int initLength) {
            this(initLength, MAX_LENGTH);
        }
    
        public LruCache(int initLength, int maxLength) {
            MAX_LENGTH = maxLength;
            map = new LinkedHashMap<K, V>(initLength, 0.75f, true) {
                @Override
                protected boolean removeEldestEntry(Entry<K, V> eldest) {
                    return size() > MAX_LENGTH;
                }
            };
        }
    
        /**
         * 添加项
         *
         * @param item  项
         * @param state 状态
         */
        public void put(K item, V state) {
            lock.writeLock().lock();
            map.put(item, state);
            lock.writeLock().unlock();
        }
    
        /**
         * 获取值,使用前请判断是否存在item
         *
         * @param item 项
         * @return value 值
         */
        public V get(String item) {
            lock.readLock().lock();
            V value = map.get(item);
            lock.readLock().unlock();
            return value;
        }
    
        /**
         * 是否存在
         *
         * @param item 项
         * @return 是否存在
         */
        public boolean containsKey(String item) {
            lock.readLock().lock();
            boolean isContainer = map.containsKey(item);
            lock.readLock().unlock();
            return isContainer;
        }
    
        /**
         * 删除item
         *
         * @param item 项
         */
        public void remove(String item) {
            lock.writeLock().lock();
            map.remove(item);
            lock.writeLock().unlock();
        }
    }

    synchronized和ReadWriteLock的区别在于:

    ReadWriteLock读写锁,当读取的时候线程会获得read锁,其他线程也可以获得read锁同时并发的去读取,但是写程序运行获取到write锁的时候,其他线程是不能进行操作的,因为write是排它锁,而synchronized不管你是read还是write没有抢到锁的线程都会被阻塞。

    3、LRUCache的hashMap实现

    需要注意的是,这段不是线程安全的,要想做到线程安全,同上两例需要加上synchronized等。

    public class LRUCache<K, V> {
    
        private Node head;
        private Node end;
        //缓存存储上限
        private int  limit;
    
        private HashMap<String, Node> hashMap;
    
        public LRUCache(int limit) {
            this.limit = limit;
            hashMap = new HashMap<String, Node>();
        }
    
        public String get(String key) {
            Node node = hashMap.get(key);
            if (node == null) {
                return null;
            }
            refreshNode(node);
            return node.value;
        }
    
        public void put(String key, String value) {
            Node node = hashMap.get(key);
            if (node == null) {
                //如果key不存在,插入key-value
                if (hashMap.size() >= limit) {
                    String oldKey = removeNode(head);
                    hashMap.remove(oldKey);
                }
                node = new Node(key, value);
                addNode(node);
                hashMap.put(key, node);
            } else {
                //如果key存在,刷新key-value
                node.value = value;
                refreshNode(node);
            }
        }
    
        public void remove(String key) {
            Node node = hashMap.get(key);
            removeNode(node);
            hashMap.remove(key);
        }
    
        /**
         * 刷新被访问的节点位置
         *
         * @param node 被访问的节点
         */
    
        private void refreshNode(Node node) {
            //如果访问的是尾节点,无需移动节点
            if (node == end) {
                return;
            }
            //移除节点
            removeNode(node);
            //重新插入节点
            addNode(node);
        }
    
        /**
         * 删除节点
         *
         * @param node 要删除的节点
         */
    
        private String removeNode(Node node) {
            if (node == end) {
                //移除尾节点
                end = end.pre;
            } else if (node == head) {
                //移除头节点
                head = head.next;
            } else {
                //移除中间节点
                node.pre.next = node.next;
                node.next.pre = node.pre;
            }
            return node.key;
        }
    
        /**
         * 尾部插入节点
         *
         * @param node 要插入的节点
         */
    
        private void addNode(Node node) {
            if (end != null) {
                end.next = node;
                node.pre = end;
                node.next = null;
            }
            end = node;
            if (head == null) {
                head = node;
            }
        }
    
        class Node {
            Node(String key, String value) {
                this.key = key;
                this.value = value;
            }
    
            public Node   pre;
            public Node   next;
            public String key;
            public String value;
        }
    
        public static void main(String[] args) {
            LRUCache lruCache = new LRUCache(5);
            lruCache.put("001", "用户1信息");
            lruCache.put("002", "用户1信息");
            lruCache.put("003", "用户1信息");
            lruCache.put("004", "用户1信息");
            lruCache.put("005", "用户1信息");
            lruCache.get("002");
            lruCache.put("004", "用户2信息更新");
            lruCache.put("006", "用户6信息");
            System.out.println(lruCache.get("001"));
            System.out.println(lruCache.get("006"));
        }
    }
    LRUCache

     

     

     

    转载于:https://www.cnblogs.com/boomoom/p/9919973.html

    展开全文
  • LRUCache LeetCode LRUCache(最近最少使用缓存)实现。 题目描述: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥...
  • LruCache (此类在android-support-v4的包中提供) 这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中...
  • LruCache是基于Lru算法实现的一种缓存机制。本文对LruCache的概念和实现原理进行介绍,通过实例分析和使用介绍,让大家更好的了解LruCache,下面跟着小编一起来看下吧
  • LRUCache 它是什么? NET的轻量级线程安全LRU缓存 我怎么才能得到它? LRUCache可作为NuGet包提供: ://www.nuget.org/packages/LRUCache PM> Install-Package LRUCache 为什么做的? 我想要一个简单,轻量级的...
  • 缓存 任务是设计和实现最近最少使用 (LRU) 缓存的数据结构。... public class LRUCache { public LRUCache(int capacity) { } public int get(int key) { } public void put(int key, int value) { } }
  • LRUCache Java中的简单LRU缓存。 “破解编码面试”中的问题16.25。 问题 设计用于Web查找的缓存机制,该机制将映射两个值,例如街道地址和营业税率。 假定这两个值是字符串,并且缓存具有最大大小并开始为空。 当...
  • LRUCache 用Java实现的小型LRUCache。 不顾编码测试而制造
  • LRUCache11仅标头的C ++ 11 LRU Cache模板类,它使您可以定义键,值和(可选)映射类型。 使用双向链接列表和std :: unordered_map样式容器提供快速插入,删除和更新LRUCache11仅标头的C ++ 11 LRU Cache模板类,该...
  • LRUCache.java

    2020-01-14 16:35:45
    lru-1缓存算法,java简单实现
  • AsyncTask的使用及ListView的常见优化 asyncTask异步加载数据 使用了LruCache优化图片加载 通过滑动监听提高ListView滑动流畅度.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习...
  • 简易单链表增删改查功能实现。新增内容:新增单链表LruCache算法增删改查,对学习LruCache 算法有一定帮助。
  • LruCache

    2018-11-23 15:21:47
    1.LruCache的基本使用 2.LruCache的源码分析 3.基于LinkedHashMap的实现 一、LruCache缓存的实例代码。 假设存的是图片· long maxMemory = (int) Runtime.getRuntime().maxMemory(); int memorySize = (int) ...

    文章主要介绍了:
    1.LruCache的基本使用
    2.LruCache的源码分析
    3.基于LinkedHashMap的实现

    一、LruCache缓存的实例代码。

    假设存的是图片·
    long  maxMemory = (int) Runtime.getRuntime().maxMemory();
            int memorySize = (int) (maxMemory/8);
            LruCache<String ,Bitmap> lruCache = new LruCache<String ,Bitmap>(memorySize){
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    return value.getByteCount();
                }
            };
    

    maxMemory是缓存定义的最大的值,不能超过这个值,负责就会被回收。
    重写sizeOf是为了计算每个数值的大小,等累计缓存的数值超出定义的最大值就会回收。

    • 操作方式:
     // 把Value对象加入到缓存中
        public void putValueToMemory(String key, Bitmap bitmap) {
            if (getValueFromMemory(key) == null) {
                lruCache.put(key, bitmap);
            }
        }
    
        // 从缓存中得到value对象
        public Bitmap getValueFromMemory(String key) {
            return lruCache.get(key);
        }
    
        // 从缓存中删除指定的value
        public void removeValueMemory(String key) {
            lruCache.remove(key);
        }
    

    二 、源码调用

    (1)属性

    public class LruCache<K, V> {
        private final LinkedHashMap<K, V> map; 核心类
    
        /** Size of this cache in units. Not necessarily the number of elements. */
        private int size;
        private int maxSize;
    
        private int putCount;
        private int createCount;
        private int evictionCount;
        private int hitCount;
        private int missCount;
    

    LinkedHashMap为核心类,Lru也是基于LinkedHashMap从而实现的。

    (2)LruCache只有一个构造方法,初始了LinkedHashMap

     public LruCache(int maxSize) {
            if (maxSize <= 0) {
                throw new IllegalArgumentException("maxSize <= 0");
            }
            this.maxSize = maxSize;
            this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
        }
    

    LinkedHashMap自身是默认 按照插入的顺序进行排序的,此处初始化的时候new LinkedHashMap<K, V>(0, 0.75f, true); 传入true则将LinkedHashMap的顺序改为访问顺序,说明Lru初始化的时候默认的是访问顺序。

    (3)LruCache的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) {对map进行操作之前,先进行同步操作
                putCount++;
                size += safeSizeOf(key, value);
                previous = map.put(key, value);
                if (previous != null) {
                    size -= safeSizeOf(key, previous);
                }
            }
    
            if (previous != null) {
                entryRemoved(false, key, previous, value);
            }
    
      
            trimToSize(maxSize);判断是否需要移除LinkedHashMap中的元素
            return previous;
        }
    

    safeSizeOf方法,是计算LruCache的已经缓存的大小.
    entryRemoved(false, key, previous, value);如果找的到对应的key的话是替换新值,不存在的话就是新增。true为删除条目生成空间,false反之.
    trimToSize判断是否需要移除LinkedHashMap中的元素

    public void trimToSize(int maxSize) {
       
           while (true) { **循环直到返回<=缓存的最大大小
               K key;
               V value;
               synchronized (this) {**同步
                   if (size < 0 || (map.isEmpty() && size != 0)) {
                       throw new IllegalStateException(getClass().getName()
                               + ".sizeOf() is reporting inconsistent results!");
                   }
     **  如果当前的size小于等于最大的size则直接返回,不需要删除数据
                   if (size <= maxSize) {
                       break;
                   }
    
               **如果size超出了最大的size,则需要进行删除数据,       
                **map.eldest获取表头的数据,进行删除
                   Map.Entry<K, V> toEvict = map.eldest();
                   if (toEvict == null) {
                       break;
                   }
    
                   key = toEvict.getKey();
                   value = toEvict.getValue();
                   map.remove(key);**删除数据
                   size -= safeSizeOf(key, value);**重新计算缓存大小
                   evictionCount++;
               }
    
               entryRemoved(true, key, value, null);
           }
       }
    

    如同上述注释中写的一样,可以看出,就是不断的循环移除LinkedHashMap双向链表表头的元素,直到缓存的大小小于等于缓存大小为止。

    • map.eldest()返回值
     public Map.Entry<K, V> eldest() {
            return head;
        }
    

    LinkedHashMap map.eldest()的调用是返回表头的集合数据head。

    LinkedHashMap继承HashMap,重写的方法中并没有重写put,所以put使用的还是HashMap的put方法,在LruCache类中呢,put相当于调用的是HashMap的put,get调用的是LinkedHashMap重写的get,此处主要就看一下这个put和get方法。在HashMap put方法中,最终会回调afterNodeAccess给LinkedHashMap,在LinkedHashMap的get方法中,最终也是走的这个方法,来操作head集合的赋值,最近的操作的数据则移到表尾。

    • LinkedHashMap中head的处理
     void afterNodeAccess(Node<K,V> e) {  move node to last
            LinkedHashMapEntry<K,V> last;
            if (accessOrder && (last = tail) != e) {
                LinkedHashMapEntry<K,V> p =
                    (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
                p.after = null;
                if (b == null)
                    head = a;
                else
                    b.after = a;
                if (a != null)
                    a.before = b;
                else
                    last = b;
                if (last == null)
                    head = p;
                else {
                    p.before = last;
                    last.after = p;
                }
                tail = p;
                ++modCount;
            }
        }
    

    对LinkedHashMap的put和get操作,都会让被操作的Entry移动到双向链表的表尾,删除数据则是从表头开始的,就符合Lru算法的要求。

    (4)LruCache的get方法是从缓存中取值:

      public final V get(K key) {
            if (key == null) {
                throw new NullPointerException("key == null");
            }
    
            V mapValue;
            synchronized (this) {  取值成功
                mapValue = map.get(key);
                if (mapValue != null) {
                    hitCount++;
                    return mapValue;
                }
                missCount++;
            }
    
            V createdValue = create(key);
            if (createdValue == null) { 通过Key尝试创建一个新值,默认返回为null。可重写
                return null;
            }
    
            synchronized (this) {
                createCount++;
    如果我们重写了create(key)方法而且返回值不为空,那么将上述的key与这个返回值写入到map当中
                mapValue = map.put(key, createdValue);
    
                if (mapValue != null) {
                    // There was a conflict so undo that last put
                    map.put(key, mapValue);
                } else {
                    size += safeSizeOf(key, createdValue);
                }
            }
    
            if (mapValue != null) {
                entryRemoved(false, key, createdValue, mapValue);
                return mapValue;
            } else {
                trimToSize(maxSize);
                return createdValue;
            }
        }
    

    V createdValue = create(key);可重写create,此处是判断当前是值是不是空的,如果不是空的,会将创建的key与createdValue 值捆绑,存到map中。

    (5)LruCache的remove方法是从缓存中去删除:

     public final V remove(K key) {
            if (key == null) {
                throw new NullPointerException("key == null");
            }
    
            V previous;
            synchronized (this) {
                previous = map.remove(key);
                if (previous != null) {
                    size -= safeSizeOf(key, previous);
                }
            }
    
            if (previous != null) {
                entryRemoved(false, key, previous, null);
            }
    
            return previous;
        }
    

    根据Key删除所对应的value值。

    总结:

    Lru是基于LinkedHashMap实现的, 默认为访问顺序。
    HashMap无序,而LinkedHashMap是有序的。序列可分为插入顺序和访问顺序,若是访问顺序,操作已存在的数据时会将其移植双链表表尾。

    展开全文
  • Android使用LruCache缓存图片,
  • LruCache缓存

    2019-07-31 18:26:11
    1、那么LruCache到底是什么呢? LruCache 是对限定数量的缓存对象持有强引用的缓存,每一次缓存对象被访问,都会被移动到队列的头部。当有对象要被添加到已经达到数量上限的 LruCache 中,队列尾部的对象将会被移除...

    Lru算法: Lru 指的是“Least Recently Used-近期最少使用算法”。
    1、那么LruCache到底是什么呢?
    LruCache 是对限定数量的缓存对象持有强引用的缓存,每一次缓存对象被访问,都会被移动到队列的头部。当有对象要被添加到已经达到数量上限的 LruCache 中,队列尾部的对象将会被移除,而且可能会被垃圾回收器回收。LruCache 中的 Lru 指的是“Least Recently Used-近期最少使用算法”。这就意味着,LruCache 是一个能够判断哪个缓存对象是近期最少使用的缓存对象,从而把最少使用的移至队尾,而近期使用的则留在队列前面了。举个例子:比如我们有a、b、c、d、e五个元素,而a、c、d、e都被访问过,唯有b元素没有访问,则b元素就成为了近期最少使用元素了,就移至在队尾了。

    从上面的叙述中我们总结可以知道LruCache核心思想就两点:

    1、LruCache使用的是近期最少使用算法,近期使用最少的将会移至到队尾,而近期刚刚使用的则会移至到头部。

    2、LruCache缓存的大小是限定的(限定的大小由我们定义),当LruCache存储空间满了就会移除队尾的而为新的对象的加入腾出控件。

    2、我们还是从源码入手学学LruCache到底怎么使用吧:
    在这里插入图片描述
    显示发现一堆int类型的变量,还有一个最重要的LinkedHashMap<K,V> 这个队列,通俗的讲LinkedHashMap<K,V>就是一个双向链表存储结构。

    各个变量的意思为:

    size - LruCache中已经存储的大小

    maxSize - 我们定义的LruCache缓存最大的空间

    putCount - put的次数(为LruCache添加缓存对象的次数)

    createCount - create的次数

    evictionCount - 回收的次数

    hitCount - 命中的次数

    missCount - 丢失的次数

    再看看构造器:

    public LruCache(int maxSize) {
            if (maxSize <= 0) {
                throw new IllegalArgumentException("maxSize <= 0");
            }
            this.maxSize = maxSize;
            this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
        }
    

    发现需要传入一个int类型的值,顾名思义,这就是我们定义的LruCache缓存的空间大小了,一般情况下我们可以得到应用程序的最大可用空间,然后按百分比取值设置给它即可。
    再看看其它一些比较重要的方法:

    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) {
                putCount++;
                size += safeSizeOf(key, value);
                previous = map.put(key, value);
                if (previous != null) {
                    size -= safeSizeOf(key, previous);
                }
            }
     
            if (previous != null) {
                entryRemoved(false, key, previous, value);
            }
     
            trimToSize(maxSize);
            return previous;
        }
    

    通过该方法我们可以知道LruCache中是通过<Key,Value>形式存储缓存数据的。意思就是我们把一个Value存储到LruCache中,并设置对应键值为key。然后判断key和value都不能为空,否则就抛异常了。之后把该Value移至队列的头部。
    get()方法:

      public final V get(K key) {
            if (key == null) {
                throw new NullPointerException("key == null");
            }
     
            V mapValue;
            synchronized (this) {
                mapValue = map.get(key);
                if (mapValue != null) {
                    hitCount++;
                    return mapValue;
                }
                missCount++;
            }
     
            /*
             * Attempt to create a value. This may take a long time, and the map
             * may be different when create() returns. If a conflicting value was
             * added to the map while create() was working, we leave that value in
             * the map and release the created value.
             */
     
            V createdValue = create(key);
            if (createdValue == null) {
                return null;
            }
     
            synchronized (this) {
                createCount++;
                mapValue = map.put(key, createdValue);
     
                if (mapValue != null) {
                    // There was a conflict so undo that last put
                    map.put(key, mapValue);
                } else {
                    size += safeSizeOf(key, createdValue);
                }
            }
     
            if (mapValue != null) {
                entryRemoved(false, key, createdValue, mapValue);
                return mapValue;
            } else {
                trimToSize(maxSize);
                return createdValue;
            }
        }
    

    该方法就是得到对应key缓存的Value,假如该Value存在,返回Value并且移至该Value至队列的头部,这也证实了最近最先使用的将会移至队列的头部。假如Value不存在则返回null。
    remove()方法:

    public final V remove(K key) {
    if (key == null) {
    throw new NullPointerException(“key == null”);
    }

    V previous;
    synchronized (this) {
        previous = map.remove(key);
        if (previous != null) {
            size -= safeSizeOf(key, previous);
        }
    }
    
    if (previous != null) {
        entryRemoved(false, key, previous, null);
    }
    
    return previous;
    

    }
    该方法就是从LruCache缓存中移除对应key的Value值。
    sizeof()方法:一般需要重写的:

     protected int sizeOf(K key, V value) {
            return 1;
        }
    

    重写它计算不同的Value的大小。一般我们会这样重写:

    mLruCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    if(bitmap!=null){
                        return bitmap.getByteCount();
                    }
                    return 0;
                }
            };
    

    好了,总结一下使用LruCache的原理:比如像ImageView中加载一张图片时候,首先会在LruCache的缓存中检查是否有对应的key值(get( key)),如果有就返回对应的Bitmap,从而更新ImageView,如果没有则重新开启一个异步线程来重新加载这张图片。

    来看看用LruCache缓存Bitmap的例子:

    public class MyLruCache extends AppCompatActivity{
        private LruCache<String,Bitmap> mLruCache;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //得到应用程序最大可用内存
            int maxCache = (int) Runtime.getRuntime().maxMemory();
            int cacheSize = maxCache / 8;//设置图片缓存大小为应用程序总内存的1/8
            mLruCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    if(bitmap!=null){
                        return bitmap.getByteCount();
                    }
                    return 0;
                }
            };
        }
        /**
         * 添加Bitmap到LruCache中
         *
         * @param key
         * @param bitmap
         */
        public void putBitmapToLruCache(String key, Bitmap bitmap) {
            if (getBitmapFromLruCache(key) == null) {
                mLruCache.put(key, bitmap);
            }
        }
     
        /**
         * @param key
         * @return 从LruCache缓存中获取一张Bitmap,没有则会返回null
         */
        public Bitmap getBitmapFromLruCache(String key) {
            return mLruCache.get(key);
        }
    }
    

    贴下主要代码:

    MainActivity:

    public class MainActivity extends ActionBarActivity {
        private GridView mGridView;
        private List<String> datas;
        private Toolbar mToolbar;
        private GridViewAdapter mAdapter;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.v("zxy", "cache:" + getCacheDir().getPath());
            Log.v("zxy", "Excache:" + getExternalCacheDir().getPath());
            mToolbar = (Toolbar) findViewById(R.id.toolbar);
            mToolbar.setTitleTextColor(Color.WHITE);
            mToolbar.setNavigationIcon(R.mipmap.icon);
            setSupportActionBar(mToolbar);
            initDatas();
     
            mGridView = (GridView) findViewById(R.id.gridView);
            mAdapter = new GridViewAdapter(this, mGridView, datas);
            mGridView.setAdapter(mAdapter);
            mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(MainActivity.this, "position=" + position + ",id=" + id, Toast.LENGTH_SHORT).show();
                }
            });
     
        }
     
        public void initDatas() {
            datas = new ArrayList<>();
            for (int i = 0; i < 55; i++) {
                datas.add(URLDatasTools.imageUrls[i]);
            }
        }
     
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mAdapter.cancelAllDownloadTask();//取消所有下载任务
        }
    }
    

    GridViewAdapter:

    public class GridViewAdapter extends BaseAdapter implements AbsListView.OnScrollListener {
        private List<DownloadTask> mDownloadTaskList;//所有下载异步线程的集合
        private Context mContext;
        private GridView mGridView;
        private List<String> datas;
        private LruCache<String, Bitmap> mLruCache;
        private int mFirstVisibleItem;//当前页显示的第一个item的位置position
        private int mVisibleItemCount;//当前页共显示了多少个item
        private boolean isFirstRunning = true;
     
        public GridViewAdapter(Context context, GridView mGridView, List<String> datas) {
            this.mContext = context;
            this.datas = datas;
            this.mGridView = mGridView;
            this.mGridView.setOnScrollListener(this);
            mDownloadTaskList = new ArrayList<>();
            initCache();
        }
     
        private void initCache() {
            //得到应用程序最大可用内存
            int maxCache = (int) Runtime.getRuntime().maxMemory();
            int cacheSize = maxCache / 8;//设置图片缓存大小为应用程序总内存的1/8
            mLruCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    if (bitmap != null) {
                        return bitmap.getByteCount();
                    }
                    return 0;
                }
            };
        }
     
        @Override
        public int getCount() {
            return datas.size();
        }
     
        @Override
        public Object getItem(int position) {
            return datas.get(position);
        }
     
        @Override
        public long getItemId(int position) {
            return position;
        }
     
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item, parent, false);
            ImageView mImageView = (ImageView) convertView.findViewById(R.id.imageView);
            TextView mTextView = (TextView) convertView.findViewById(R.id.textView);
            String url = datas.get(position);
            mImageView.setTag(String2MD5Tools.hashKeyForDisk(url));//设置一个Tag为md5(url),保证图片不错乱显示
            mTextView.setText("第" + position + "项");
            setImageViewForBitmap(mImageView, url);
            return convertView;
     
        }
     
        /**
         * 给ImageView设置Bitmap
         *
         * @param imageView
         * @param url
         */
        private void setImageViewForBitmap(ImageView imageView, String url) {
            String key = String2MD5Tools.hashKeyForDisk(url);//对url进行md5编码
            Bitmap bitmap = getBitmapFromLruCache(key);
            if (bitmap != null) {
                //如果缓存中存在,那么就设置缓存中的bitmap
                imageView.setImageBitmap(bitmap);
            } else {
                //不存在就设置个默认的背景色
                imageView.setBackgroundResource(R.color.color_five);
            }
        }
     
        /**
         * 添加Bitmap到LruCache中
         *
         * @param key
         * @param bitmap
         */
        public void putBitmapToLruCache(String key, Bitmap bitmap) {
            if (getBitmapFromLruCache(key) == null) {
                mLruCache.put(key, bitmap);
            }
        }
     
        /**
         * @param key
         * @return 从LruCache缓存中获取一张Bitmap,没有则会返回null
         */
        public Bitmap getBitmapFromLruCache(String key) {
            return mLruCache.get(key);
        }
     
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (scrollState == SCROLL_STATE_IDLE) {//GridView为静止状态时,让它去下载图片
                loadBitmap(mFirstVisibleItem, mVisibleItemCount);
            } else {
                //滚动时候取消所有下载任务
                cancelAllDownloadTask();
            }
        }
     
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            mFirstVisibleItem = firstVisibleItem;
            mVisibleItemCount = visibleItemCount;
            if (isFirstRunning && visibleItemCount > 0) {//首次进入时加载图片
                loadBitmap(mFirstVisibleItem, mVisibleItemCount);
                isFirstRunning = false;
            }
        }
     
        /**
         * 加载图片到ImageView中
         *
         * @param mFirstVisibleItem
         * @param mVisibleItemCount
         */
        private void loadBitmap(int mFirstVisibleItem, int mVisibleItemCount) {
            //首先判断图片在不在缓存中,如果不在就开启异步线程去下载该图片
            for (int i = mFirstVisibleItem; i < mFirstVisibleItem + mVisibleItemCount; i++) {
                final String url = datas.get(i);
                String key = String2MD5Tools.hashKeyForDisk(url);
                Bitmap bitmap = getBitmapFromLruCache(key);
                if (bitmap != null) {
                    //缓存中存在该图片的话就设置给ImageView
                    ImageView mImageView = (ImageView) mGridView.findViewWithTag(String2MD5Tools.hashKeyForDisk(url));
                    if (mImageView != null) {
                        mImageView.setImageBitmap(bitmap);
                    }
                } else {
                    //不存在的话就开启一个异步线程去下载
                    DownloadTask task = new DownloadTask();
                    mDownloadTaskList.add(task);//把下载任务添加至下载集合中
                    task.execute(url);
                }
            }
        }
     
        class DownloadTask extends AsyncTask<String, Void, Bitmap> {
            String url;
            @Override
            protected Bitmap doInBackground(String... params) {
                //在后台开始下载图片
                url = params[0];
                Bitmap bitmap = downloadBitmap(url);
                if (bitmap != null) {
                    //把下载好的图片放入LruCache中
                    String key = String2MD5Tools.hashKeyForDisk(url);
                    putBitmapToLruCache(key, bitmap);
                }
                return bitmap;
            }
     
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                //把下载好的图片显示出来
                ImageView mImageView = (ImageView) mGridView.findViewWithTag(String2MD5Tools.hashKeyForDisk(url));
                if (mImageView != null && bitmap != null) {
                    mImageView.setImageBitmap(bitmap);
                    mDownloadTaskList.remove(this);//把下载好的任务移除
                }
            }
     
        }
     
        /**
         * @param tasks
         * 取消所有的下载任务
         */
        public void cancelAllDownloadTask(){
            if(mDownloadTaskList!=null){
                for (int i = 0; i < mDownloadTaskList.size(); i++) {
                    mDownloadTaskList.get(i).cancel(true);
                }
            }
        }
        /**
         * 建立网络链接下载图片
         *
         * @param urlStr
         * @return
         */
        private Bitmap downloadBitmap(String urlStr) {
            HttpURLConnection connection = null;
            Bitmap bitmap = null;
            try {
                URL url = new URL(urlStr);
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(5000);
                connection.setReadTimeout(5000);
                connection.setDoInput(true);
                connection.connect();
                if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream mInputStream = connection.getInputStream();
                    bitmap = BitmapFactory.decodeStream(mInputStream);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
            return bitmap;
        }
    

    }

    展开全文
  • 前端开源库-lrucache

    2019-08-29 17:52:45
    前端开源库-lrucachelru cache,node.js/browser的lru缓存。
  • 在Py3K里,自带一个cache模块,使用「LRU算法」,能够缓存一些函数或方法放返回值,目前我还在玩Py2K,因此土鳖的造了一个轮子,取名「LruCache.py」,不叫特点的特点:「单进程支持线程安全」 示例代码: import ...
  • Python中的LRU缓存 用于学习目的的Python中LRU缓存的简单实现。 数据结构 在此实现中,我们使用LRU缓存的经典版本,该版本是使用双链表和哈希映射实现的。 我们有一个自定义的双链表实现。 双链表 ...
  • LRUCache2 在此作业之前,我对 LRU 缓存及其工作原理知之甚少,因此我使用以下材料来了解有关 LRU 缓存及其工作原理的更多信息: 资源: 维基百科: 优酷视频: 关于如何在 JS 中编码 LRU 缓存的中篇文章: Python ...
  • LruCache实例demo

    2016-08-11 10:31:21
    LruCache实例demo 详情请看:http://blog.csdn.net/zxw136511485/article/details/52153287 Android 缓存浅谈(一)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,193
精华内容 9,677
关键字:

lrucache