LruCache.java这个类用来作为缓存图片是很不错的,源码的分析:
来源:互联网 发布:淘宝加盟被骗了有合同 编辑:程序博客网 时间:2024/05/18 02:03
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/**
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
android.util;
import
java.util.LinkedHashMap;
import
java.util.Map;
/***
* A cache that holds strong references to a limited number of values. Each time
* a value is accessed, it is moved to the head of a queue. When a value is
* added to a full cache, the value at the end of that queue is evicted and may
* become eligible for garbage collection.
*
* <p>If your cached values hold resources that need to be explicitly released,
* override {<a href="\"http://www.eoeandroid.com/home.php?mod=space&uid=91636\"" target="\"_blank\"">@link</a> #entryRemoved}.
*
* <p>If a cache miss should be computed on demand for the corresponding keys,
* override {@link #create}. This simplifies the calling code, allowing it to
* assume a value will always be returned, even when there's a cache miss.
*
* <p>By default, the cache size is measured in the number of entries. Override
* {@link #sizeOf} to size the cache in different units. For example, this cache
* is limited to 4MiB of bitmaps:
* <pre> {@code
* int cacheSize = 4 * 1024 * 1024; // 4MiB
* LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
* protected int sizeOf(String key, Bitmap value) {
* return value.getByteCount();
* }
* }}</pre>
*
* <p>This class is thread-safe. Perform multiple cache operations atomically by
* synchronizing on the cache: <pre> {@code
* synchronized (cache) {
* if (cache.get(key) == null) {
* cache.put(key, value);
* }
* }}</pre>
*
* <p>This class does not allow null to be used as a key or value. A return
* value of null from {@link #get}, {@link #put} or {@link #remove} is
* unambiguous: the key was not in the cache.
*/
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;
//已经存储的大小,缓存中所占用的字节,初始0,将通过此变量严格控制缓存所占用的堆内存
private
int
maxSize;
//缓存只能占用的最大堆内存,这个在构造函数里面就需要传参数确定大小的
private
int
putCount;
//put的次数
private
int
createCount;
//create的次数
private
int
evictionCount;
//回收的次数
private
int
hitCount;
//命中的次数
private
int
missCount;
//丢失的次数
/***
* @param maxSize for caches that do not override {@link #sizeOf}, this is
* the maximum number of entries in the cache. For all other caches,
* this is the maximum sum of the sizes of the entries in this cache.
*/
public
LruCache(
int
maxSize) {
if
(maxSize <=
0
) {
throw
new
IllegalArgumentException(
"maxSize <= 0"
);
}
this
.maxSize = maxSize;
//LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列,即LRU
//这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率
this
.map =
new
LinkedHashMap<K, V>(
0
,
0
.75f,
true
);
}
/***
* Returns the value for {<a href="\"http://www.eoeandroid.com/home.php?mod=space&uid=38354\"" target="\"_blank\"">@Code</a> key} if it exists in the cache or can be
* created by {@code #create}. If a value was returned, it is moved to the
* head of the queue. This returns null if a value is not cached and cannot
* be created.
*/
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);
//这个默认都是返回为null,需要我们自己去实现它
if
(createdValue ==
null
) {
return
null
;
}
/**
* LinkedHashMapMap不支持线程同步。
* 这里为了防止任一时刻可以有多个线程同时写LinkedHashMapMap可能会导致数据的不一致所以使用了同步机制
*/
synchronized
(
this
) {
createCount++;
//如果当前map中没有key值则返回的是null,如果已经存在相同的key值则返回的值是之前该key所保存的value值
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;
}
}
/***
* Caches {@code value} for {@code key}. The value is moved to the head of
* the queue.
*
* <a href="\"http://www.eoeandroid.com/home.php?mod=space&uid=7300\"" target="\"_blank\"">@return</a> the previous value mapped by {@code key}.
*/
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;
}
/***
* @param maxSize the maximum size of the cache before returning. May be -1
* to evict even 0-sized elements.
* 这个方法主要是比较当前的存储容量和总容量的大小即 size和maxSize,
* 如果当前容量大于总容量的大小就比较将最近最少使用的元素来替换以提高效率
* 如果知道是最近最少主要是在于
* LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列
*/
private
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!"
);
}
if
(size <= maxSize) {
break
;
}
Map.Entry<K, V> toEvict = map.eldest();
//这个eldest()方法可以理解为取出map最前面的那个值
if
(toEvict ==
null
) {
break
;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
//这里是移除改值之后要把该值所占用的存储空间去掉
evictionCount++;
}
//这个方法不会默认不会做任何处理,如果有需要我们可以去实现该方法去做我们想做的事
entryRemoved(
true
, key, value,
null
);
}
}
/***
* Removes the entry for {@code key} if it exists.
*
* @return the previous value mapped by {@code key}.
* 移除指定key的value值
*/
public
final
V remove(K key) {
if
(key ==
null
) {
throw
new
NullPointerException(
"key == null"
);
}
V previous;
synchronized
(
this
) {
previous = map.remove(key);
//这个是返回该key的value值
if
(previous !=
null
) {
size -= safeSizeOf(key, previous);
}
}
if
(previous !=
null
) {
entryRemoved(
false
, key, previous,
null
);
}
return
previous;
}
/***
* Called for entries that have been evicted or removed. This method is
* invoked when a value is evicted to make space, removed by a call to
* {@link #remove}, or replaced by a call to {@link #put}. The default
* implementation does nothing.
*
* <p>The method is called without synchronization: other threads may
* access the cache while this method is executing.
*
* @param evicted true if the entry is being removed to make space, false
* if the removal was caused by a {@link #put} or {@link #remove}.
* @param newValue the new value for {@code key}, if it exists. If non-null,
* this removal was caused by a {@link #put}. Otherwise it was caused by
* an eviction or a {@link #remove}.
* 在移除某一个值时会调用这个方法,包括容量不够系统主动移除以及插入重复的key时要移除该key的上一个value值
* 这个方法默认不做任何处理,我们可以自己去实现该方法做我们想做的事情
*/
protected
void
entryRemoved(
boolean
evicted, K key, V oldValue, V newValue) {}
/***
* Called after a cache miss to compute a value for the corresponding key.
* Returns the computed value or null if no value can be computed. The
* default implementation returns null.
*
* <p>The method is called without synchronization: other threads may
* access the cache while this method is executing.
*
* <p>If a value for {@code key} exists in the cache when this method
* returns, the created value will be released with {@link #entryRemoved}
* and discarded. This can occur when multiple threads request the same key
* at the same time (causing multiple values to be created), or when one
* thread calls {@link #put} while another is creating a value for the same
* key.
* 这个方法试在get的时候如果没有该key值时执行的方法,这个默认是直接返回null
* 我们可以自行重写该方法做我们想要做的处理
*/
protected
V create(K key) {
return
null
;
}
/**
* 计算当前key值所对应的value的存储容量
*/
private
int
safeSizeOf(K key, V value) {
int
result = sizeOf(key, value);
if
(result <
0
) {
throw
new
IllegalStateException(
"Negative size: "
+ key +
"="
+ value);
}
return
result;
}
/***
* Returns the size of the entry for {@code key} and {@code value} in
* user-defined units. The default implementation returns 1 so that size
* is the number of entries and max size is the maximum number of entries.
*
* <p>An entry's size must not change while it is in the cache.
* 这个safeSizeOf()方法调用来计算该key值所对应的存储容量
* 默认是方法回1,但是在应用中我们一般都要去重写改方法来返回实际value的大小,列如下面的代码就是计算Bitmap的大小
* 计算Bitmap内存占用也可以是bitmap.getRowBytes() * bitmap.getHeight();
* LruCache<String,Bitmap> mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
* @Override
* protected int sizeOf(String key, Bitmap bitmap) {
* return bitmap.getByteCount() / 1024;
* }
* };
*/
protected
int
sizeOf(K key, V value) {
return
1
;
}
/***
* Clear the cache, calling {@link #entryRemoved} on each removed entry.
* 这个一看就是清空cacke
*/
public
final
void
evictAll() {
trimToSize(-
1
);
// -1 will evict 0-sized elements
}
/***
* For caches that do not override {@link #sizeOf}, this returns the number
* of entries in the cache. For all other caches, this returns the sum of
* the sizes of the entries in this cache.
* 当前已经已经存储容量的大小
*/
public
synchronized
final
int
size() {
return
size;
}
/***
* For caches that do not override {@link #sizeOf}, this returns the maximum
* number of entries in the cache. For all other caches, this returns the
* maximum sum of the sizes of the entries in this cache.
* 总容量的大小
*/
public
synchronized
final
int
maxSize() {
return
maxSize;
}
/***
* Returns the number of times {@link #get} returned a value that was
* already present in the cache.
*/
public
synchronized
final
int
hitCount() {
return
hitCount;
}
/***
* Returns the number of times {@link #get} returned null or required a new
* value to be created.
*/
public
synchronized
final
int
missCount() {
return
missCount;
}
/***
* Returns the number of times {@link #create(Object)} returned a value.
*/
public
synchronized
final
int
createCount() {
return
createCount;
}
/***
* Returns the number of times {@link #put} was called.
*/
public
synchronized
final
int
putCount() {
return
putCount;
}
/***
* Returns the number of values that have been evicted.
*/
public
synchronized
final
int
evictionCount() {
return
evictionCount;
}
/***
* Returns a copy of the current contents of the cache, ordered from least
* recently accessed to most recently accessed.
* 返回当前cache的副本,从最近最少访问到最多访问
*/
public
synchronized
final
Map<K, V> snapshot() {
return
new
LinkedHashMap<K, V>(map);
}
/**
* 这个主要是返回内存使用的情况
*/
@Override
public
synchronized
final
String toString() {
int
accesses = hitCount + missCount;
int
hitPercent = accesses !=
0
? (
100
* hitCount / accesses) :
0
;
return
String.format(
"LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]"
,
maxSize, hitCount, missCount, hitPercent);
}
}
- LruCache.java这个类用来作为缓存图片是很不错的,源码的分析:
- 图片的LruCache缓存和DiskLruCache缓存
- Android LruCache 缓存 类 源码 注解 分析
- 很不错的UBOOT源码分析
- 这个贴是用来放链接的
- LruCache缓存处理及异步加载图片类的封装
- LruCache的实现原理(图片三级缓存)
- 源码分析1:Android的LruCache类分析
- android 提供的内存缓存LruCache.java
- 【Android 开发】深入理解内存缓存类LruCache:源码分析
- Android中LruCache的源码分析
- 从HashMap到LruCache的源码分析
- 从HashMap到LruCache的源码分析
- LruCache缓存类源码解析
- Android缓存源码分析(DiskLruCache,LruCache)
- 这个demo是一个同事给我的,看上去效果很不错,分享给大家
- 这个博客是用来记录学习html5的,好好学习天天向上~
- 这个是用来被解析的XML文件
- 列表下拉/上拉刷新:EGORefreshTableHeaderView使用,定义EGORefreshTableFooterView
- Zigbee学习(一)之新建Zstack协议栈工程
- hdu2571 命运
- XMPP协议分析-原理篇
- HDU2698+字符串
- LruCache.java这个类用来作为缓存图片是很不错的,源码的分析:
- Hive基本命令整理
- java静态代理与动态代理
- Java中的JVM基础:数据类型和堆栈
- XMPP协议分析—具体篇
- 里氏代换原则
- dp学习笔记
- android 程序防止被360或者系统给kill掉
- MSM8x25 LCD调试分析(三)