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的方法隘道,有必要復(fù)習(xí)下 synchronized 相關(guān)的操作
synchronized 相關(guān)的 操作
在Java中,synchronized關(guān)鍵字是用來控制線程同步的,就是在多線程的環(huán)境下,控制synchronized代碼段不被多個線程同時執(zhí)行。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 有多少,如果只要里面的元素尺寸 小與了他的最大值表窘,為們就會退出循環(huán)典予,不然就會去remove,也就是hashMap的remove乐严, size -= safesizeof(),計算緩存對象的大小瘤袖,最后會掉一個entryremove(),這個方法是個 空方法昂验。如果我們想在lru 算法中做一些二級緩存的話捂敌,可以實現(xiàn)這方法。這就是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 優(yōu)化,無非就是 合適的時間去加載合適大小的圖片简僧,不可能把每一張原圖大小都加載到內(nèi)存中建椰,所以有個 縮放比,把真實的的 高跟要求的高岛马,做個比例棉姐,返回
// 根據(jù)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;
}
縮略圖
根據(jù)insampleSize的值來保存相應(yīng)的bitmap。
有個很重要的屬性啦逆,inJustDecodeBounds.經(jīng)差
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.
意思就是說如果該值設(shè)為true那么將不返回實際的bitmap不給其分配內(nèi)存空間而里面只包括一些解碼邊界信息即圖片大小信息伞矩,那么相應(yīng)的方法也就出來了,通過設(shè)置inJustDecodeBounds為true蹦浦,獲取到outHeight(圖片原始高度)和 outWidth(圖片的原始寬度),然后計算一個inSampleSize(縮放值)撞蜂,然后就可以取圖片了盲镶,這里要注意的是,inSampleSize 可能小于0蝌诡,必須做判斷溉贿。也就是說先將Options的屬性inJustDecodeBounds設(shè)為true,先獲取圖片的基本大小信息數(shù)據(jù)(信息沒有保存在bitmap里面浦旱,而是保存在options里面)宇色,通過options.outHeight和 options. outWidth獲取的大小信息以及自己想要到得圖片大小計算出來縮放比例inSampleSize,然后緊接著將inJustDecodeBounds設(shè)為false颁湖,就可以根據(jù)已經(jīng)得到的縮放比例得到自己想要的圖片縮放圖了宣蠕。
//縮略圖
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;
}
三級緩存
- 網(wǎng)絡(luò)緩存
- 內(nèi)存緩存
- 本地緩存
直接走內(nèi)存或者本地緩存,不走流量甥捺。
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);
}