android 提供的内存缓存LruCache.java
来源:互联网 发布:linux 笔试题 编辑:程序博客网 时间:2024/05/16 16:16
LruCache.java这个类用来作为缓存图片是很不错的,下面是我对源码的分析:
转自:http://www.eoeandroid.com/thread-286816-1-1.html
001
/**
002
* Copyright (C) 2011 The Android Open Source Project
003
*
004
* Licensed under the Apache License, Version 2.0 (the "License");
005
* you may not use this file except in compliance with the License.
006
* You may obtain a copy of the License at
007
*
008
* http://www.apache.org/licenses/LICENSE-2.0
009
*
010
* Unless required by applicable law or agreed to in writing, software
011
* distributed under the License is distributed on an "AS IS" BASIS,
012
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013
* See the License for the specific language governing permissions and
014
* limitations under the License.
015
*/
016
017
package
android.util;
018
019
import
java.util.LinkedHashMap;
020
import
java.util.Map;
021
022
/***
023
* A cache that holds strong references to a limited number of values. Each time
024
* a value is accessed, it is moved to the head of a queue. When a value is
025
* added to a full cache, the value at the end of that queue is evicted and may
026
* become eligible for garbage collection.
027
*
028
* <p>If your cached values hold resources that need to be explicitly released,
029
* override {<A href='\"http://www.eoeandroid.com/home.php?mod=space&uid=91636\"' target='\"_blank\"'>@link</A> #entryRemoved}.
030
*
031
* <p>If a cache miss should be computed on demand for the corresponding keys,
032
* override {@link #create}. This simplifies the calling code, allowing it to
033
* assume a value will always be returned, even when there's a cache miss.
034
*
035
* <p>By default, the cache size is measured in the number of entries. Override
036
* {@link #sizeOf} to size the cache in different units. For example, this cache
037
* is limited to 4MiB of bitmaps:
038
* <pre> {@code
039
* int cacheSize = 4 * 1024 * 1024; // 4MiB
040
* LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
041
* protected int sizeOf(String key, Bitmap value) {
042
* return value.getByteCount();
043
* }
044
* }}</pre>
045
*
046
* <p>This class is thread-safe. Perform multiple cache operations atomically by
047
* synchronizing on the cache: <pre> {@code
048
* synchronized (cache) {
049
* if (cache.get(key) == null) {
050
* cache.put(key, value);
051
* }
052
* }}</pre>
053
*
054
* <p>This class does not allow null to be used as a key or value. A return
055
* value of null from {@link #get}, {@link #put} or {@link #remove} is
056
* unambiguous: the key was not in the cache.
057
*/
058
public
class
LruCache<K, V> {
059
private
final
LinkedHashMap<K, V> map;
060
061
/*** Size of this cache in units. Not necessarily the number of elements. */
062
private
int
size;
//已经存储的大小,缓存中所占用的字节,初始0,将通过此变量严格控制缓存所占用的堆内存
063
private
int
maxSize;
//缓存只能占用的最大堆内存,这个在构造函数里面就需要传参数确定大小的
064
065
private
int
putCount;
//put的次数
066
private
int
createCount;
//create的次数
067
private
int
evictionCount;
//回收的次数
068
private
int
hitCount;
//命中的次数
069
private
int
missCount;
//丢失的次数
070
071
/***
072
* @param maxSize for caches that do not override {@link #sizeOf}, this is
073
* the maximum number of entries in the cache. For all other caches,
074
* this is the maximum sum of the sizes of the entries in this cache.
075
*/
076
public
LruCache(
int
maxSize) {
077
if
(maxSize <=
0
) {
078
throw
new
IllegalArgumentException(
"maxSize <= 0"
);
079
}
080
this
.maxSize = maxSize;
081
082
//LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列,即LRU
083
//这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率
084
this
.map =
new
LinkedHashMap<K, V>(
0
,
0
.75f,
true
);
085
}
086
087
/***
088
* 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
089
* created by {@code #create}. If a value was returned, it is moved to the
090
* head of the queue. This returns null if a value is not cached and cannot
091
* be created.
092
*/
093
public
final
V get(K key) {
094
if
(key ==
null
) {
095
throw
new
NullPointerException(
"key == null"
);
096
}
097
098
V mapValue;
099
synchronized
(
this
) {
100
mapValue = map.get(key);
101
if
(mapValue !=
null
) {
102
hitCount++;
103
return
mapValue;
104
}
105
missCount++;
106
}
107
108
/**
109
* Attempt to create a value. This may take a long time, and the map
110
* may be different when create() returns. If a conflicting value was
111
* added to the map while create() was working, we leave that value in
112
* the map and release the created value.
113
*/
114
115
V createdValue = create(key);
//这个默认都是返回为null,需要我们自己去实现它
116
if
(createdValue ==
null
) {
117
return
null
;
118
}
119
120
/**
121
* LinkedHashMapMap不支持线程同步。
122
* 这里为了防止任一时刻可以有多个线程同时写LinkedHashMapMap可能会导致数据的不一致所以使用了同步机制
123
*/
124
synchronized
(
this
) {
125
createCount++;
126
//如果当前map中没有key值则返回的是null,如果已经存在相同的key值则返回的值是之前该key所保存的value值
127
mapValue = map.put(key, createdValue);
128
129
if
(mapValue !=
null
) {
130
// There was a conflict so undo that last put
131
map.put(key, mapValue);
132
}
else
{
//计算当前的容量
133
size += safeSizeOf(key, createdValue);
134
}
135
}
136
137
if
(mapValue !=
null
) {
138
entryRemoved(
false
, key, createdValue, mapValue);
139
return
mapValue;
140
}
else
{
141
trimToSize(maxSize);
142
return
createdValue;
143
}
144
}
145
146
/***
147
* Caches {@code value} for {@code key}. The value is moved to the head of
148
* the queue.
149
*
150
* <A href='\"http://www.eoeandroid.com/home.php?mod=space&uid=7300\"' target='\"_blank\"'>@return</A> the previous value mapped by {@code key}.
151
*/
152
public
final
V put(K key, V value) {
153
if
(key ==
null
|| value ==
null
) {
154
throw
new
NullPointerException(
"key == null || value == null"
);
155
}
156
157
V previous;
158
synchronized
(
this
) {
159
putCount++;
160
size += safeSizeOf(key, value);
161
previous = map.put(key, value);
162
if
(previous !=
null
) {
163
size -= safeSizeOf(key, previous);
164
}
165
}
166
167
if
(previous !=
null
) {
168
entryRemoved(
false
, key, previous, value);
169
}
170
171
trimToSize(maxSize);
172
return
previous;
173
}
174
175
/***
176
* @param maxSize the maximum size of the cache before returning. May be -1
177
* to evict even 0-sized elements.
178
* 这个方法主要是比较当前的存储容量和总容量的大小即 size和maxSize,
179
* 如果当前容量大于总容量的大小就比较将最近最少使用的元素来替换以提高效率
180
* 如果知道是最近最少主要是在于
181
* LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列
182
*/
183
private
void
trimToSize(
int
maxSize) {
184
while
(
true
) {
185
K key;
186
V value;
187
synchronized
(
this
) {
188
if
(size <
0
|| (map.isEmpty() && size !=
0
)) {
189
throw
new
IllegalStateException(getClass().getName()
190
+
".sizeOf() is reporting inconsistent results!"
);
191
}
192
193
if
(size <= maxSize) {
194
break
;
195
}
196
197
Map.Entry<K, V> toEvict = map.eldest();
//这个eldest()方法可以理解为取出map最前面的那个值
198
if
(toEvict ==
null
) {
199
break
;
200
}
201
202
key = toEvict.getKey();
203
value = toEvict.getValue();
204
map.remove(key);
205
size -= safeSizeOf(key, value);
//这里是移除改值之后要把该值所占用的存储空间去掉
206
evictionCount++;
207
}
208
209
//这个方法不会默认不会做任何处理,如果有需要我们可以去实现该方法去做我们想做的事
210
entryRemoved(
true
, key, value,
null
);
211
}
212
}
213
214
/***
215
* Removes the entry for {@code key} if it exists.
216
*
217
* @return the previous value mapped by {@code key}.
218
* 移除指定key的value值
219
*/
220
public
final
V remove(K key) {
221
if
(key ==
null
) {
222
throw
new
NullPointerException(
"key == null"
);
223
}
224
225
V previous;
226
synchronized
(
this
) {
227
previous = map.remove(key);
//这个是返回该key的value值
228
if
(previous !=
null
) {
229
size -= safeSizeOf(key, previous);
230
}
231
}
232
233
if
(previous !=
null
) {
234
entryRemoved(
false
, key, previous,
null
);
235
}
236
237
return
previous;
238
}
239
240
/***
241
* Called for entries that have been evicted or removed. This method is
242
* invoked when a value is evicted to make space, removed by a call to
243
* {@link #remove}, or replaced by a call to {@link #put}. The default
244
* implementation does nothing.
245
*
246
* <p>The method is called without synchronization: other threads may
247
* access the cache while this method is executing.
248
*
249
* @param evicted true if the entry is being removed to make space, false
250
* if the removal was caused by a {@link #put} or {@link #remove}.
251
* @param newValue the new value for {@code key}, if it exists. If non-null,
252
* this removal was caused by a {@link #put}. Otherwise it was caused by
253
* an eviction or a {@link #remove}.
254
* 在移除某一个值时会调用这个方法,包括容量不够系统主动移除以及插入重复的key时要移除该key的上一个value值
255
* 这个方法默认不做任何处理,我们可以自己去实现该方法做我们想做的事情
256
*/
257
protected
void
entryRemoved(
boolean
evicted, K key, V oldValue, V newValue) {}
258
259
/***
260
* Called after a cache miss to compute a value for the corresponding key.
261
* Returns the computed value or null if no value can be computed. The
262
* default implementation returns null.
263
*
264
* <p>The method is called without synchronization: other threads may
265
* access the cache while this method is executing.
266
*
267
* <p>If a value for {@code key} exists in the cache when this method
268
* returns, the created value will be released with {@link #entryRemoved}
269
* and discarded. This can occur when multiple threads request the same key
270
* at the same time (causing multiple values to be created), or when one
271
* thread calls {@link #put} while another is creating a value for the same
272
* key.
273
* 这个方法试在get的时候如果没有该key值时执行的方法,这个默认是直接返回null
274
* 我们可以自行重写该方法做我们想要做的处理
275
*/
276
protected
V create(K key) {
277
return
null
;
278
}
279
280
/**
281
* 计算当前key值所对应的value的存储容量
282
*/
283
private
int
safeSizeOf(K key, V value) {
284
int
result = sizeOf(key, value);
285
if
(result <
0
) {
286
throw
new
IllegalStateException(
"Negative size: "
+ key +
"="
+ value);
287
}
288
return
result;
289
}
290
291
/***
292
* Returns the size of the entry for {@code key} and {@code value} in
293
* user-defined units. The default implementation returns 1 so that size
294
* is the number of entries and max size is the maximum number of entries.
295
*
296
* <p>An entry's size must not change while it is in the cache.
297
* 这个safeSizeOf()方法调用来计算该key值所对应的存储容量
298
* 默认是方法回1,但是在应用中我们一般都要去重写改方法来返回实际value的大小,列如下面的代码就是计算Bitmap的大小
299
* 计算Bitmap内存占用也可以是bitmap.getRowBytes() * bitmap.getHeight();
300
* LruCache<String,Bitmap> mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
301
* @Override
302
* protected int sizeOf(String key, Bitmap bitmap) {
303
* return bitmap.getByteCount() / 1024;
304
* }
305
* };
306
*/
307
protected
int
sizeOf(K key, V value) {
308
return
1
;
309
}
310
311
/***
312
* Clear the cache, calling {@link #entryRemoved} on each removed entry.
313
* 这个一看就是清空cacke
314
*/
315
public
final
void
evictAll() {
316
trimToSize(-
1
);
// -1 will evict 0-sized elements
317
}
318
319
/***
320
* For caches that do not override {@link #sizeOf}, this returns the number
321
* of entries in the cache. For all other caches, this returns the sum of
322
* the sizes of the entries in this cache.
323
* 当前已经已经存储容量的大小
324
*/
325
public
synchronized
final
int
size() {
326
return
size;
327
}
328
329
/***
330
* For caches that do not override {@link #sizeOf}, this returns the maximum
331
* number of entries in the cache. For all other caches, this returns the
332
* maximum sum of the sizes of the entries in this cache.
333
* 总容量的大小
334
*/
335
public
synchronized
final
int
maxSize() {
336
return
maxSize;
337
}
338
339
/***
340
* Returns the number of times {@link #get} returned a value that was
341
* already present in the cache.
342
*/
343
public
synchronized
final
int
hitCount() {
344
return
hitCount;
345
}
346
347
/***
348
* Returns the number of times {@link #get} returned null or required a new
349
* value to be created.
350
*/
351
public
synchronized
final
int
missCount() {
352
return
missCount;
353
}
354
355
/***
356
* Returns the number of times {@link #create(Object)} returned a value.
357
*/
358
public
synchronized
final
int
createCount() {
359
return
createCount;
360
}
361
362
/***
363
* Returns the number of times {@link #put} was called.
364
*/
365
public
synchronized
final
int
putCount() {
366
return
putCount;
367
}
368
369
/***
370
* Returns the number of values that have been evicted.
371
*/
372
public
synchronized
final
int
evictionCount() {
373
return
evictionCount;
374
}
375
376
/***
377
* Returns a copy of the current contents of the cache, ordered from least
378
* recently accessed to most recently accessed.
379
* 返回当前cache的副本,从最近最少访问到最多访问
380
*/
381
public
synchronized
final
Map<K, V> snapshot() {
382
return
new
LinkedHashMap<K, V>(map);
383
}
384
385
/**
386
* 这个主要是返回内存使用的情况
387
*/
388
@Override
public
synchronized
final
String toString() {
389
int
accesses = hitCount + missCount;
390
int
hitPercent = accesses !=
0
? (
100
* hitCount / accesses) :
0
;
391
return
String.format(
"LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]"
,
392
maxSize, hitCount, missCount, hitPercent);
393
}
394
}
0 0
- android 提供的内存缓存LruCache.java
- Android内存缓存LruCache
- Android 内存缓存 LruCache
- Android LruCache(内存缓存)
- Android LruCache(内存缓存)
- android LruCache的使用 (本地缓存+内存缓存)
- LruCache(内存缓存)的原理
- Android 缓存(1)---内存缓存LruCache
- Android bitmap 的缓存-LruCache
- android LruCache内存缓存源码解析
- Android LruCache内存缓存实现详解
- Android LruCache内存缓存实现详解
- Android内存缓存LruCache源码解析
- Android缓存机制Lrucache内存缓存和DiskLruCache磁盘缓存
- Android提供的LruCache类简介
- Android提供的LruCache类简介
- Android提供的LruCache类简介
- Android提供的LruCache类简介
- zookeeper python接口
- poj 1611 The Suspects(并查集模板题)
- win7操作系统配置环境变量
- 免杀基础知识总结
- 关键字之this和super
- android 提供的内存缓存LruCache.java
- Android中利用App实现消息推送机制的代码
- linux网络协议栈流程
- 走进C++程序世界-----operator new delete 重载
- 无法逾越的一米七
- 避免nrpe端进程监控多个接口
- 数据库编程
- FOJ 2170 花生的序列 dp
- 详解使用sax解析xml文件的DefaultHandler处理类(转载)