recycle() 方法
后面会补上
LRU --->LruCache<k,v> 这个类需要看看
进行三级缓存
- LinkedHashMap<k,v> map ; 保存一个强引用的缓存对象。
- trimToSize(int maxSize) {} 缓存满的时候,算法就会移除较早的缓存对象,然后把新的缓存对象添加到队列种
- get() remove()
- put() 缓存的添加和 获取操作
有用到一个entryRemoved() 空方法
* Caches {@code value} for {@code key}. The value is moved to the head of
* the queue.
*
* @return 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;
}
以上为 put的方法,有必要复习下 synchronized 相关的操作
synchronized 相关的 操作
在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。synchronized既可以加在一段代码上,也可以加在方法上。
http://blog.csdn.net/xiao__gui/article/details/8188833
synchronized锁住的是代码还是对象: synchronized锁住的是括号里的对象
trimTosize()
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!");
}
if (size <= maxSize) {
break;
}
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);
}
}
这方法是Lru 算法的核心,做一个判断,计算剩余的size 有多少,如果只要里面的元素尺寸 小与了他的最大值,为们就会退出循环,不然就会去remove,也就是hashMap的remove, size -= safesizeof(),计算缓存对象的大小,最后会掉一个entryremove(),这个方法是个 空方法。如果我们想在lru 算法中做一些二级缓存的话,可以实现这方法。这就是trimtosize方法,会把最老的最不常用的缓存对象从我们的缓存队列中移除。
put方法
用的是LinkedHashmap,所以跟正常的map 放入一样。 但是 加了:还是同步代码块,然后还是计算 size的大小, previous = map.put(key, value); 看看 previous 是否为空,得出新的size大小。同样 掉了 entryremove。
* Caches {@code value} for {@code
key}. The value is moved to the head of
* the queue.
*
* @return 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;
}
remove()
/**
* Removes the entry for {@code key} if it exists.
*
* @return the previous value mapped by {@code key}.
*/
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;
}
计算inSampleSize 的值
bitmap 优化,无非就是 合适的时间去加载合适大小的图片,不可能把每一张原图大小都加载到内存中,所以有个 缩放比,把真实的的 高跟要求的高,做个比例,返回
// 根据maxWidth, maxHeight计算最合适的inSampleSize
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
缩略图
根据insampleSize的值来保存相应的bitmap。
有个很重要的属性,inJustDecodeBounds.经差
If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
意思就是说如果该值设为true那么将不返回实际的bitmap不给其分配内存空间而里面只包括一些解码边界信息即图片大小信息,那么相应的方法也就出来了,通过设置inJustDecodeBounds为true,获取到outHeight(图片原始高度)和 outWidth(图片的原始宽度),然后计算一个inSampleSize(缩放值),然后就可以取图片了,这里要注意的是,inSampleSize 可能小于0,必须做判断。也就是说先将Options的属性inJustDecodeBounds设为true,先获取图片的基本大小信息数据(信息没有保存在bitmap里面,而是保存在options里面),通过options.outHeight和 options. outWidth获取的大小信息以及自己想要到得图片大小计算出来缩放比例inSampleSize,然后紧接着将inJustDecodeBounds设为false,就可以根据已经得到的缩放比例得到自己想要的图片缩放图了。
//缩略图
public static Bitmap thumbnail(String path,
int maxWidth, int maxHeight, boolean autoRotate) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 获取这个图片的宽和高信息到options中, 此时返回bm为空
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false;
// 计算缩放比
int sampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inPurgeable = true;
options.inInputShareable = true;
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
三级缓存
- 网络缓存
- 内存缓存
- 本地缓存
直接走内存或者本地缓存,不走流量。
some code
//保存bitmap
public static String save(Bitmap bitmap,
Bitmap.CompressFormat format, int quality, File destFile) {
try {
FileOutputStream out = new FileOutputStream(destFile);
if (bitmap.compress(format, quality, out)) {
out.flush();
out.close();
}
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
return destFile.getAbsolutePath();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
and
// 保存到sd卡
public static String save(Bitmap bitmap,
Bitmap.CompressFormat format, int quality, Context context) {
if (!Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) {
return null;
}
File dir = new File(Environment.getExternalStorageDirectory()
+ "/" + context.getPackageName() + "/save/");
if (!dir.exists()) {
dir.mkdirs();
}
File destFile = new File(dir, UUID.randomUUID().toString());
return save(bitmap, format, quality, destFile);
}
网友评论