简析Android中LruCache缓存类

  1. By default, the cache size is measured in the number of entries. Override

  2. * {@link #sizeOf} to size the cache in different units. For example, this cache

  3. * is limited to 4MiB of bitmaps: 默认cache大小是测量的item的数量,重写sizeof计算不同item的大小。

  4.    {@code

  5. *   int cacheSize = 4 * 1024 * 1024; // 4MiB

  6. *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {

  7. *       protected int sizeOf(String key, Bitmap value) {

  8. *           return value.getByteCount();

  9. *       }

  10. *   }}

  11. *

  12. This class is thread-safe. Perform multiple cache operations atomically by

  13. * synchronizing on the cache: 

       {@code

  14. *   synchronized (cache) {

  15. *     if (cache.get(key) == null) {

  16. *         cache.put(key, value);

  17. *     }

  18. *   }}

  19. *

  20. This class does not allow null to be used as a key or value. A return

  21. * value of null from {@link #get}, {@link #put} or {@link #remove} is

  22. * unambiguous: the key was not in the cache.

  23. * 不允许key或者value为null  当get(),put(),remove()返回值为null时,key相应的项不在cache中

  24. */

  25. public class LruCache<K, V> {

  26. private final LinkedHashMap<K, V> map;

  27. /** Size of this cache in units. Not necessarily the number of elements. */

  28. private int size; //已经存储的大小

  29. private int maxSize; //规定的最大存储空间

  30. private int putCount;  //put的次数

  31. private int createCount;  //create的次数

  32. private int evictionCount;  //回收的次数

  33. private int hitCount;  //命中的次数

  34. private int missCount;  //丢失的次数

  35. /**

  36. * @param maxSize for caches that do not override {@link #sizeOf}, this is

  37. *     the maximum number of entries in the cache. For all other caches,

  38. *     this is the maximum sum of the sizes of the entries in this cache.

  39. */

  40. public LruCache(int maxSize) {

  41. if (maxSize <= 0) {

  42. throw new IllegalArgumentException(“maxSize <= 0”);

  43. }

  44. this.maxSize = maxSize;

  45. this.map = new LinkedHashMap<K, V>(0, 0.75f, true);

  46. }

  47. /**

  48. * Returns the value for {@code key} if it exists in the cache or can be

  49. * created by {@code #create}. If a value was returned, it is moved to the

  50. * head of the queue. This returns null if a value is not cached and cannot

  51. * be created. 通过key返回相应的item,或者创建返回相应的item。相应的item会移动到队列的头部,

  52. * 如果item的value没有被cache或者不能被创建,则返回null。

  53. */

  54. public final V get(K key) {

  55. if (key == null) {

  56. throw new NullPointerException(“key == null”);

  57. }

  58. V mapValue;

  59. synchronized (this) {

  60. mapValue = map.get(key);

  61. if (mapValue != null) {

  62. hitCount++;  //命中

  63. return mapValue;

  64. }

  65. missCount++;  //丢失

  66. }

  67. /*

  68. * Attempt to create a value. This may take a long time, and the map

  69. * may be different when create() returns. If a conflicting value was

  70. * added to the map while create() was working, we leave that value in

  71. * the map and release the created value.

  72. * 如果丢失了就试图创建一个item

  73. */

  74. V createdValue = create(key);

  75. if (createdValue == null) {

  76. return null;

  77. }

  78. synchronized (this) {

  79. createCount++;//创建++

  80. mapValue = map.put(key, createdValue);

  81. if (mapValue != null) {

  82. // There was a conflict so undo that last put

  83. //如果前面存在oldValue,那么撤销put()

  84. map.put(key, mapValue);

  85. } else {

  86. size += safeSizeOf(key, createdValue);

  87. }

  88. }

  89. if (mapValue != null) {

  90. entryRemoved(false, key, createdValue, mapValue);

  91. return mapValue;

  92. } else {

  93. trimToSize(maxSize);

  94. return createdValue;

  95. }

  96. }

  97. /**

  98. * Caches {@code value} for {@code key}. The value is moved to the head of

  99. * the queue.

  100. *

  101. * @return the previous value mapped by {@code key}.

  102. */

  103. public final V put(K key, V value) {

  104. if (key == null || value == null) {

  105. throw new NullPointerException(“key == null || value == null”);

  106. }

  107. V previous;

  108. synchronized (this) {

  109. putCount++;

  110. size += safeSizeOf(key, value);

  111. previous = map.put(key, value);

  112. if (previous != null) {  //返回的先前的value值

  113. size -= safeSizeOf(key, previous);

  114. }

  115. }

  116. if (previous != null) {

  117. entryRemoved(false, key, previous, value);

  118. }

  119. trimToSize(maxSize);

  120. return previous;

  121. }

  122. /**

  123. * @param maxSize the maximum size of the cache before returning. May be -1

  124. *     to evict even 0-sized elements.

  125. *  清空cache空间

  126. */

  127. private void trimToSize(int maxSize) {

  128. while (true) {

  129. K key;

  130. V value;

  131. synchronized (this) {

  132. if (size < 0 || (map.isEmpty() && size != 0)) {

  133. throw new IllegalStateException(getClass().getName()

  134. + “.sizeOf() is reporting inconsistent results!”);

  135. }

  136. if (size <= maxSize) {

  137. break;

  138. }

  139. Map.Entry<K, V> toEvict = map.eldest();

  140. if (toEvict == null) {

  141. break;

  142. }

  143. key = toEvict.getKey();

  144. value = toEvict.getValue();

  145. map.remove(key);

  146. size -= safeSizeOf(key, value);

  147. evictionCount++;

  148. }

  149. entryRemoved(true, key, value, null);

  150. }

  151. }

  152. /**

  153. * Removes the entry for {@code key} if it exists.

  154. * 删除key相应的cache项,返回相应的value

  155. * @return the previous value mapped by {@code key}.

  156. */

  157. public final V remove(K key) {

  158. if (key == null) {

  159. throw new NullPointerException(“key == null”);

  160. }

  161. V previous;

  162. synchronized (this) {

  163. previous = map.remove(key);

  164. if (previous != null) {

  165. size -= safeSizeOf(key, previous);

  166. }

  167. }

  168. if (previous != null) {

  169. entryRemoved(false, key, previous, null);

  170. }

  171. return previous;

  172. }

  173. /**

  174. * Called for entries that have been evicted or removed. This method is

  175. * invoked when a value is evicted to make space, removed by a call to

  176. * {@link #remove}, or replaced by a call to {@link #put}. The default

  177. * implementation does nothing.

  178. * 当item被回收或者删掉时调用。改方法当value被回收释放存储空间时被remove调用,

  179. * 或者替换item值时put调用,默认实现什么都没做。

  180. The method is called without synchronization: other threads may

  181. * access the cache while this method is executing.

  182. *

  183. * @param evicted true if the entry is being removed to make space, false

  184. *     if the removal was caused by a {@link #put} or {@link #remove}.

  185. * true—为释放空间被删除;false—put或remove导致

  186. * @param newValue the new value for {@code key}, if it exists. If non-null,

  187. *     this removal was caused by a {@link #put}. Otherwise it was caused by

  188. *     an eviction or a {@link #remove}.

  189. */

  190. protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}

  191. /**

  192. * Called after a cache miss to compute a value for the corresponding key.

  193. * Returns the computed value or null if no value can be computed. The

  194. * default implementation returns null.

  195. * 当某Item丢失时会调用到,返回计算的相应的value或者null

  196. The method is called without synchronization: other threads may

  197. * access the cache while this method is executing.

  198. *

  199. If a value for {@code key} exists in the cache when this method

  200. * returns, the created value will be released with {@link #entryRemoved}

  201. * and discarded. This can occur when multiple threads request the same key

  202. * at the same time (causing multiple values to be created), or when one

  203. * thread calls {@link #put} while another is creating a value for the same

  204. * key.

  205. */

  206. protected V create(K key) {

  207. return null;

  208. }

  209. private int safeSizeOf(K key, V value) {

  210. int result = sizeOf(key, value);

  211. if (result < 0) {

  212. throw new IllegalStateException("Negative size: " + key + “=” + value);

  213. }

《设计思想解读开源框架》

第一章、 热修复设计

  • 第一节、 AOT/JIT & dexopt 与 dex2oat

  • 第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题

  • 第三节、热修复设计之热修复原理

  • 第四节、Tinker 的集成与使用(自动补丁包生成)

    第二章、 插件化框架设计

  • 第一节、 Class 文件与 Dex 文件的结构解读

  • 第二节、 Android 资源加载机制详解

  • 第三节、 四大组件调用原理

  • 第四节、 so 文件加载机制

  • 第五节、 Android 系统服务实现原理

    第三章、 组件化框架设计

  • 第一节、阿里巴巴开源路由框——ARouter 原理分析

  • 第二节、APT 编译时期自动生成代码&动态类加载

  • 第三节、 Java SPI 机制

  • 第四节、 AOP&IOC

  • 第五节、 手写组件化架构

    第四章、图片加载框架

  • 第一节、图片加载框架选型

  • 第二节、Glide 原理分析

  • 第三节、手写图片加载框架实战

    第五章、网络访问框架设计

  • 第一节、网络通信必备基础

  • 第二节、OkHttp 源码解读

  • 第三节、Retrofit 源码解析

    第六章、 RXJava 响应式编程框架设计

  • 第一节、链式调用

  • 第二节、 扩展的观察者模式

  • 第三节、事件变换设计

  • 第四节、Scheduler 线程控制

    第七章、 IOC 架构设计

  • 第一节、 依赖注入与控制反转

  • 第二节、ButterKnife 原理上篇、中篇、下篇

  • 第三节、Dagger 架构设计核心解密

    第八章、 Android 架构组件 Jetpack

  • 第一节、 LiveData 原理

  • 第二节、 Navigation 如何解决 tabLayout 问题

  • 第三节、 ViewModel 如何感知 View 生命周期及内核原理

  • 第四节、 Room 架构方式方法

  • 第五节、 dataBinding 为什么能够支持 MVVM

  • 第六节、 WorkManager 内核揭秘

  • 第七节、 Lifecycles 生命周期


    本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

第二节、 Navigation 如何解决 tabLayout 问题

  • 第三节、 ViewModel 如何感知 View 生命周期及内核原理

  • 第四节、 Room 架构方式方法

  • 第五节、 dataBinding 为什么能够支持 MVVM

  • 第六节、 WorkManager 内核揭秘

  • 第七节、 Lifecycles 生命周期

    [外链图片转存中…(img-8kYe2Tif-1714679367412)]
    本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
    [外链图片转存中…(img-SdaVMUvE-1714679367412)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值