西北野狼
我的github: https://github.com/soyoungboy
我的segmentfault: http://segmentfault.com/u/soyoungboy
【不积跬步,无以至千里;不积小流,无以成江海】
博客园 首页 新随笔 联系 订阅
管理
【推荐】微信小程序一站式部署 多场景模板定制
最新IT新闻:
· SpaceX创始人钱包丢了?随跑车一起飞向了太空
· AirPods耳机冒烟 苹果公司已经介入调查
· DeepMind团队训练深度学习新方法:像人一样玩游戏
· FB开始测试“不赞” 为避免负能量名字改成“踩”
· 彭博社探访《旅行青蛙》开发团队:创意者没写过代码
» 更多新闻...
最新知识库文章:
· 领域驱动设计在互联网业务开发中的实践
· 步入云计算
· 以操作系统的角度述说线程与进程
· 软件测试转型之路
· 门内门外看招聘
» 更多知识库文章... 昵称:西北野狼
园龄:4年6个月
粉丝: 34
关注: 3 +加关注
我的github: https://github.com/soyoungboy
我的segmentfault: http://segmentfault.com/u/soyoungboy
【不积跬步,无以至千里;不积小流,无以成江海】
博客园 首页 新随笔 联系 订阅
管理
LruCache的使用及原理
采用LRU算法实现的话就是将最老的数据删掉。利用LRU缓存,我们能够提高系统的性能. 一,是它本身已经实现了按照访问顺序的存储,也就是说,最近读取的会放在最前面,最不常读取的会放在最后(当然,它也可以实现按照插入顺序存储)。 二,LinkedHashMap本身有一个方法用于判断是否需要移除最不常读取的数,但是,原始方法默认不需要移除(这是,LinkedHashMap相当于一个linkedlist),所以,我们需要override这样一个方法,使得当缓存里存放的数据个数超过规定个数后,就把最不常用的移除掉。 源码分析: 1 /**
2 * Static library version of {@link android.util.LruCache}. Used to write apps
3 * that run on API levels prior to 12. When running on API level 12 or above,
4 * this implementation is still used; it does not try to switch to the
5 * framework's implementation. See the framework SDK documentation for a class
6 * overview.
7 */
8 public class LruCache<K, V> {
9 /**缓存 map 集合,要用LinkedHashMap */
10 private final LinkedHashMap<K, V> map;
11
12 /**缓存大小 */
13 private int size;
14 /**最大缓存大小*/
15 private int maxSize;
16 /**put的次数*/
17 private int putCount;
18 /**create的次数*/
19 private int createCount;
20 /**回收的次数*/
21 private int evictionCount;
22 /**命中的次数*/
23 private int hitCount;
24 /**丢失的次数*/
25 private int missCount;
26
27 /**
28 *构造方法,maxSize最大缓存大小,初始化LinkedHashMap
29 */
30 public LruCache(int maxSize) {
31 if (maxSize <= 0) {
32 throw new IllegalArgumentException("maxSize <= 0");
33 }
34 this.maxSize = maxSize;
35 //将LinkedHashMap的accessOrder设置为true来实现LRU
36 //false 插入顺序
37 //true 访问顺序
38 this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
39 }
40
41 /**
42 * 重新设置最大缓存大小
43 * @param maxSize 最大缓存大小.
44 */
45 public void resize(int maxSize) {
46 if (maxSize <= 0) {
47 throw new IllegalArgumentException("maxSize <= 0");
48 }
49
50 synchronized (this) {
51 this.maxSize = maxSize;
52 }
53 trimToSize(maxSize);
54 }
55
56 /**
57 如果缓存中存在或者被创建过,返回该值,如果已经返回了,会被移动到队列头部,如果没有被缓存和创建,会被返回null
58 */
59 public final V get(K key) {
60 if (key == null) {
61 throw new NullPointerException("key == null");
62 }
63
64 V mapValue;
65 synchronized (this) {
66 mapValue = map.get(key);
67 if (mapValue != null) {
68 hitCount++;
69 return mapValue;
70 }
71 missCount++;
72 }
73
74 /*
75 *如果丢失了就试图创建一个item
76 */
77
78 V createdValue = create(key);
79 if (createdValue == null) {
80 return null;
81 }
82
83 synchronized (this) {
84 createCount++;
85 mapValue = map.put(key, createdValue);
86
87 if (mapValue != null) {
88 // There was a conflict so undo that last put
89 map.put(key, mapValue);
90 } else {
91 size += safeSizeOf(key, createdValue);
92 }
93 }
94
95 if (mapValue != null) {
96 entryRemoved(false, key, createdValue, mapValue);
97 return mapValue;
98 } else {
99 //每次新加入对象都需要调用trimToSize方法看是否需要回收
100 trimToSize(maxSize);
101 return createdValue;
102 }
103 }
104
105 /**
106 *会被移动到队列头部
107 * @return the previous value mapped by {@code key}.
108 */
109 public final V put(K key, V value) {
110 if (key == null || value == null) {
111 throw new NullPointerException("key == null || value == null");
112 }
113
114 V previous;
115 synchronized (this) {
116 putCount++;
117 //size加上预put对象的大小
118 size += safeSizeOf(key, value);
119 previous = map.put(key, value);
120 if (previous != null) {
121 //如果之前存在键为key的对象,则size应该减去原来对象的大小
122 size -= safeSizeOf(key, previous);
123 }
124 }
125
126 if (previous != null) {
127 entryRemoved(false, key, previous, value);
128 }
129 //每次新加入对象都需要调用trimToSize方法看是否需要回收
130 trimToSize(maxSize);
131 return previous;
132 }
133
134 /**
135 * 删除最老的条目,直到其余条目的总数达到或低于要求的大小。
136 */
137 public void trimToSize(int maxSize) {
138 while (true) {
139 K key;
140 V value;
141 synchronized (this) {
142 if (size < 0 || (map.isEmpty() && size != 0)) {
143 throw new IllegalStateException(getClass().getName()
144 + ".sizeOf() is reporting inconsistent results!");
145 }
146 //如果当前size小于maxSize或者map没有任何对象,则结束循环
147 if (size <= maxSize || map.isEmpty()) {
148 break;
149 }
150 //移除链表头部的元素,并进入下一次循环
151 Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
152 key = toEvict.getKey();
153 value = toEvict.getValue();
154 map.remove(key);
155 size -= safeSizeOf(key, value);
156 //回收次数+1
157 evictionCount++;
158 }
159
160 entryRemoved(true, key, value, null);
161 }
162 }
163
164 /**
165 *从内存缓存中根据key值移除某个对象并返回该对象
166 */
167 public final V remove(K key) {
168 if (key == null) {
169 throw new NullPointerException("key == null");
170 }
171
172 V previous;
173 synchronized (this) {
174 previous = map.remove(key);
175 if (previous != null) {
176 size -= safeSizeOf(key, previous);
177 }
178 }
179
180 if (previous != null) {
181 entryRemoved(false, key, previous, null);
182 }
183
184 return previous;
185 }
186
187 /**
188 * Called for entries that have been evicted or removed. This method is
189 * invoked when a value is evicted to make space, removed by a call to
190 * {@link #remove}, or replaced by a call to {@link #put}. The default
191 * implementation does nothing.
192 *当item被回收或者删掉时调用。改方法当value被回收释放存储空间时被remove调用,
193 * 或者替换item值时put调用,默认实现什么都没做
194 * <p>The method is called without synchronization: other threads may
195 * access the cache while this method is executing.
196 *
197 * @param evicted true if the entry is being removed to make space, false
198 * if the removal was caused by a {@link #put} or {@link #remove}.
199 * true---为释放空间被删除;false---put或remove导致
200 * @param newValue the new value for {@code key}, if it exists. If non-null,
201 * this removal was caused by a {@link #put}. Otherwise it was caused by
202 * an eviction or a {@link #remove}.
203 */
204 protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
205
206 /**
207 * Called after a cache miss to compute a value for the corresponding key.
208 * Returns the computed value or null if no value can be computed. The
209 * default implementation returns null.
210 *
211 * <p>The method is called without synchronization: other threads may
212 * access the cache while this method is executing.
213 *
214 * <p>If a value for {@code key} exists in the cache when this method
215 * returns, the created value will be released with {@link #entryRemoved}
216 * and discarded. This can occur when multiple threads request the same key
217 * at the same time (causing multiple values to be created), or when one
218 * thread calls {@link #put} while another is creating a value for the same
219 * key.
220 * 当某Item丢失时会调用到,返回计算的相应的value或者null
221 */
222 protected V create(K key) {
223 return null;
224 }
225
226 private int safeSizeOf(K key, V value) {
227 int result = sizeOf(key, value);
228 if (result < 0) {
229 throw new IllegalStateException("Negative size: " + key + "=" + value);
230 }
231 return result;
232 }
233
234 /**
235 * Returns the size of the entry for {@code key} and {@code value} in
236 * user-defined units. The default implementation returns 1 so that size
237 * is the number of entries and max size is the maximum number of entries.
238 *
239 * <p>An entry's size must not change while it is in the cache.
240 *这个方法要特别注意,跟我们实例化LruCache的maxSize要呼应,怎么做到呼应呢,比如maxSize的大小为缓存
241 *的个数,这里就是return 1就ok,如果是内存的大小,如果5M,这个就不能是个数了,就需要覆盖这个方法,返回每个缓存
242 *value的size大小,如果是Bitmap,这应该是bitmap.getByteCount();
243 */
244 protected int sizeOf(K key, V value) {
245 return 1;
246 }
247
248 /**
249 * Clear the cache, calling {@link #entryRemoved} on each removed entry.
250 * 清理缓存
251 */
252 public final void evictAll() {
253 trimToSize(-1); // -1 will evict 0-sized elements
254 }
255
256 /**
257 * For caches that do not override {@link #sizeOf}, this returns the number
258 * of entries in the cache. For all other caches, this returns the sum of
259 * the sizes of the entries in this cache.
260 * 缓存大小
261 */
262 public synchronized final int size() {
263 return size;
264 }
265
266 /**
267 * For caches that do not override {@link #sizeOf}, this returns the maximum
268 * number of entries in the cache. For all other caches, this returns the
269 * maximum sum of the sizes of the entries in this cache.
270 * 缓存最大值
271 */
272 public synchronized final int maxSize() {
273 return maxSize;
274 }
275
276 /**
277 * Returns the number of times {@link #get} returned a value that was
278 * already present in the cache.
279 *返回{@link#get}返回值的次数,该值为
280 *已存在于缓存中。
281 */
282 public synchronized final int hitCount() {
283 return hitCount;
284 }
285
286 /**
287 * Returns the number of times {@link #get} returned null or required a new
288 * value to be created.
289 *返回创建或者返回null的次数
290 */
291 public synchronized final int missCount() {
292 return missCount;
293 }
294
295 /**
296 * Returns the number of times {@link #create(Object)} returned a value.
297 返回创建一个元素的次数
298 */
299 public synchronized final int createCount() {
300 return createCount;
301 }
302
303 /**
304 * Returns the number of times {@link #put} was called.
305 调用put返回次数
306 */
307 public synchronized final int putCount() {
308 return putCount;
309 }
310
311 /**
312 * Returns the number of values that have been evicted.
313 * 返回已被逐出的值的数目。
314 */
315 public synchronized final int evictionCount() {
316 return evictionCount;
317 }
318
319 /**
320 * Returns a copy of the current contents of the cache, ordered from least
321 * recently accessed to most recently accessed.
322 * 返回缓存拷贝,排序规则为最近最多访问
323 */
324 public synchronized final Map<K, V> snapshot() {
325 return new LinkedHashMap<K, V>(map);
326 }
327
328 /**
329 * 返回maxSize hits misses hitRate值
330 * LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%
331 */
332 @Override public synchronized final String toString() {
333 int accesses = hitCount + missCount;
334 int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
335 return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
336 maxSize, hitCount, missCount, hitPercent);
337 }
338 }
实际使用:
public class BitmapCacheActivity extends Activity {
private ImageView iv_picture;
private BitmapCache<String, Bitmap> mMemoryCache;
private BitmapCache.BitmapRemovedCallBack<String> mEnteryRemovedCallBack =
new BitmapCache.BitmapRemovedCallBack<String>() {
@Override
public void onBitmapRemoved(String key) {
//处理回收bitmap前,清空相关view的bitmap操作
mMemoryCache.remove(key);
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bitmapcache);
iv_picture = findViewById(R.id.iv_picture);
// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
// BitmapCache通过构造函数传入缓存值,以bit为单位。
int memClass = ((ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
// 使用单个应用最大可用内存值的1/8作为缓存的大小。
int cacheSize = 1024 * 1024 * memClass / 8;
mMemoryCache = new BitmapCache<>(cacheSize, mEnteryRemovedCallBack);
loadBitmap(R.mipmap.ic_launcher_round, iv_picture);
}
/**
* bitmap添加到缓存中去
* @param key
* @param bitmap
*/
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
/**
* 从缓存中获取bitmap
* @param key
* @return
*/
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
/**
* 加载bitmap
* @param resId
* @param imageView
*/
public void loadBitmap(int resId, ImageView imageView) {
final String imageKey = String.valueOf(resId);
final Bitmap bitmap = getBitmapFromMemCache(imageKey);
//从缓存里面获取,没有设置默认的,然后在进行一步缓存操作
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.person_image_empty);
BitmapLoadingTask task = new BitmapLoadingTask(imageView);
task.execute(resId);
}
}
class BitmapLoadingTask extends AsyncTask<Integer, Void, Bitmap> {
private ImageView imageView;
public BitmapLoadingTask(ImageView imageView) {
this.imageView = imageView;
}
// 在后台加载图片。
@Override
protected Bitmap doInBackground(Integer... params) {
final Bitmap bitmap = decodeSampledBitmapFromResource(
getResources(), params[0], 100, 100);
addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
//显示在bitmap上
imageView.setImageBitmap(bitmap);
}
public Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
}
}
posted on 2018-02-07 17:40 西北野狼 阅读(6) 评论(0) 编辑 收藏 刷新评论刷新页面返回顶部 注册用户登录后才能发表评论,请 登录 或 注册, 访问网站首页。 【推荐】超50万VC++源码: 大型工控、组态\仿真、建模CAD源码2018!
【推荐】微信小程序一站式部署 多场景模板定制
最新IT新闻:· SpaceX创始人钱包丢了?随跑车一起飞向了太空
· AirPods耳机冒烟 苹果公司已经介入调查
· DeepMind团队训练深度学习新方法:像人一样玩游戏
· FB开始测试“不赞” 为避免负能量名字改成“踩”
· 彭博社探访《旅行青蛙》开发团队:创意者没写过代码
» 更多新闻...
最新知识库文章:· 领域驱动设计在互联网业务开发中的实践
· 步入云计算
· 以操作系统的角度述说线程与进程
· 软件测试转型之路
· 门内门外看招聘
» 更多知识库文章... 昵称:西北野狼
园龄:4年6个月
粉丝: 34
关注: 3 +加关注
|
||||||
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
|---|---|---|---|---|---|---|
| 28 | 29 | 30 | 31 | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
搜索
常用链接
我的标签
- android 5.0(16)
- ormlite(3)
- AndroidGradle(2)
- java复习(2)
- swift object c学习(1)
- Swift or Object c(1)
随笔分类
- 【android 面试】(12)
- 【android】(195)
- 【android--bug】(33)
- 【android--openGL】(1)
- 【androidstudio--学习和使用经验】(2)
- 【android--Thread--线程池的使用】(1)
- 【android--性能优化】(19)
- 【App研发录读书笔记】(6)
- 【Effactive Java】(2)
- 【Eventbus】(7)
- 【Gradle学习】
- 【html5】(6)
- 【IOS】(3)
- 【J2EE】(22)
- 【J2EE面试题】(2)
- 【Java -- JDBC 学习】(12)
- 【java 1.8 新特性学习】
- 【Java NIO -- IO高级进阶】(7)
- 【java 基础复习】(5)
- 【JavaWeb】(2)
- 【java多线程 -- 高级进阶】(10)
- 【JDK源码学习】(3)
- 【json异常】(2)
- 【maven学习】(4)
- 【MySQL】(1)
- 【phoneGap学习】(1)
- 【python 学习】(11)
- 【Rxjava学习】(1)
- 【Servlet】(2)
- 【shell脚本学习】
- 【sqlite高级进阶】(1)
- 【Volley学习和源码分析】(7)
- 【Web前端 -- JavaScript 学习和复习】(8)
- 【Web前端--Html&Css学习复习】(39)
- 【产品知识学习】
- 【计划】(1)
- 【设计模式复习】(26)
- 【深入理解java虚拟机】(2)
- 【数据结构与算法】(6)
- 【移动支付】(3)
- 【重构-改善既有代码的设计】
- 【自定义控件】(7)
随笔档案
- 2018年2月 (1)
- 2017年11月 (3)
- 2017年10月 (8)
- 2017年9月 (9)
- 2017年8月 (11)
- 2017年7月 (4)
- 2017年6月 (26)
- 2017年5月 (22)
- 2017年4月 (40)
- 2017年3月 (18)
- 2017年2月 (11)
- 2017年1月 (9)
- 2016年9月 (5)
- 2016年8月 (6)
- 2016年7月 (2)
- 2016年6月 (4)
- 2016年5月 (7)
- 2016年4月 (8)
- 2016年3月 (2)
- 2016年2月 (2)
- 2016年1月 (2)
- 2015年12月 (6)
- 2015年11月 (10)
- 2015年10月 (10)
- 2015年9月 (11)
- 2015年8月 (5)
- 2015年7月 (13)
- 2015年6月 (6)
- 2015年5月 (17)
- 2015年4月 (10)
- 2015年3月 (6)
- 2015年2月 (4)
- 2015年1月 (19)
- 2014年12月 (15)
- 2014年11月 (11)
- 2014年10月 (1)
- 2014年9月 (2)
- 2014年8月 (4)
- 2014年7月 (2)
- 2014年6月 (2)
- 2014年5月 (17)
- 2014年4月 (11)
- 2014年3月 (6)
- 2014年2月 (4)
- 2014年1月 (17)
- 2013年12月 (38)
- 2013年11月 (21)
- 2013年10月 (2)
- 2013年9月 (1)
- 2013年8月 (7)
My github
我的个人博客站点
积分与排名
- 积分 - 110870
- 排名 - 2670
最新评论
- 1. Re:J2EE--常见面试题总结 -- 一
- mark
- --Jason928
- 2. Re:LinkedHashMap 源码解析
- @稻花谢谢,也欢迎多多指点和建议...
- --西北野狼
- 3. Re:LinkedHashMap 源码解析
- 非常不错
- --稻花
- 4. Re:项目实战之集成邮件开发
- 不错!
- --天边里
- 5. Re:Spring -- AOP
- @BillySir通过 ProceedingJoinPoint 或者JoinPoint...
- --西北野狼
阅读排行榜
- 1. Glide加载圆形图片(13862)
- 2. androidstudio--gsonformat--超爽的数据解析方式(9896)
- 3. android app 集成 支付宝支付 微信支付(6347)
- 4. 项目中处理android 6.0权限管理问题(4409)
- 5. Activity生命周期方法调用finish后的不同表现(4382)
评论排行榜
- 1. material design 的android开源代码整理(4)
- 2. Spring -- AOP(2)
- 3. 如何在使用eclipse的情况下,清理android项目中的冗余class文件和资源文件以及冗余图片(2)
- 4. android使用shape做selector按钮按下和弹起的动画(2)
- 5. java泛型操作复习,以及讲解在android中使用的场景(2)
推荐排行榜
- 1. material design 的android开源代码整理(8)
- 2. 某技术大牛的帖子(android项目总结)(1)
- 3. android经典开源代码集合(1)
- 4. android -- 加载gif 防止oom(1)
- 5. android 实现透明状态栏(1)