一,Bitmap的高效加載
-
如何加載一個圖片?
BitmapFactiory提供了四個方法:
decodeFile:從文件系統(tǒng)加載Bitmap對象
decodeResource:從資源中加載
decodeStream:通過輸入流加載
decodeByteArray:通過字節(jié)數(shù)組加載
其中decodeFile與decodeResource又間接調(diào)用了decodeStream -
如何高效的加載Bitmap思路?
采用BitmapFactory.Options 來加載所需尺寸的圖片,因?yàn)橛械臅r候我們控件所顯示的圖片尺寸沒有圖片那么大,所以可以將其縮小,按照一定的采樣率來加載圖片從而降低內(nèi)存的占用避免OOM统翩。
通過BitmapFactory.Options來進(jìn)行縮放圖片,主要用到inSampleSize參數(shù)此洲,當(dāng)inSampleSize為1時厂汗,采用后的圖片大小為原始大小,當(dāng)inSampleSize大于時 比如為2時則采用后的圖片寬高均為原來的1/2呜师,像素為原來的1/4娶桦,占有的內(nèi)存大小也為原來的1/4 -
如何獲取采樣率
(1)將BitmapFactory.Options的inJustDecodeBounds的參數(shù)設(shè)為true并加載圖片
(2)從itmapFactory.Options中取出圖片的原始寬高信息
(3)根據(jù)采樣率的規(guī)則,以及目標(biāo)view展示的大小,計算出采樣率inSampleSize
(4)將itmapFactory.Options的inJustDecodeBounds參數(shù)設(shè)為false衷畦,重新加載圖片
注:inJustDecodeBounds設(shè)為true只會解析圖片的寬高信息栗涂,不會真的加載圖片。
public static Bitmap decodeSampledBitmapFromResource(Resources resources, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds=false;
return BitmapFactory.decodeResource(resources, resId, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int inSampleSize = 1;
final int width = options.outWidth;
final int height = options.outHeight;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
mImageView,setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.id.imageview,100,100))
二祈争,Android中的緩存策略
-
LRUCache(線程安全)
LRU算法:近期最少使用算法
是一個泛型類斤程,內(nèi)部采用一個LinkedHashMap以強(qiáng)引用的方式存儲外界的緩存對象,提供了get菩混,put的方法來完成緩存的獲取和添加忿墅,當(dāng)緩存滿的時會將較早使用的緩存對象進(jìn)行移除,再添加新的緩存對象沮峡。
強(qiáng)引用:直接對象的引用
軟引用:當(dāng)對象只有軟引用存在的時候疚脐,系統(tǒng)內(nèi)存不足時,此對象會隨時被gc回收
弱引用:當(dāng)對象只有弱引用存在時邢疙,隨時都有可能被GC回收
LruCache的實(shí)現(xiàn)
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight()/1024;
}
};
設(shè)置緩存以及獲取緩存
獲取緩存
mMemoryCache.get(key);
設(shè)置緩存
mMemoryCache.put(key,bitmap);
刪除緩存
mMemoryCache.remove(key);
-
DiskLruCache
用于實(shí)現(xiàn)存儲設(shè)備的緩存棍弄,即磁盤緩存。通過將緩存對象寫入文件系統(tǒng)從而實(shí)現(xiàn)緩存效果疟游。
DiskLruCache的創(chuàng)建
public static DiskLruCache open(File directory,int appVersion,int valueCount,long maxSize);
第一個參數(shù):表示磁盤緩存的文件系統(tǒng)中的路徑(可以在SD卡上的緩存目錄照卦,也可以選擇其他位置)
第二個參數(shù):表示應(yīng)用版本號設(shè)置為1即可
第三個參數(shù):設(shè)置為1即可
第四個參數(shù):緩存最大值,當(dāng)超過這個值乡摹,DIskLruCache會清除一些緩存
long DISK_CACHE_SIZE=1024*1024*50;
File diskCacheDir=this.getCacheDir();
if(!diskCacheDir.exists()){
diskCacheDir.mkdir();
}
mDiskLruCache=DIsLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);
DiskLruCache的緩存添加
通過Editor完成的,Editor表示一個緩存對象的編輯對象采转,首先需要獲取圖片url所對應(yīng)的key聪廉,然后通過key就可以通過edit()來獲取到Editor對象,如果這個緩存正在編輯則edit()會返回空故慈,即不允許同事彼岸奇偶及一個緩存對象板熊,一般采用url的md5值來表示key丢胚。
通過Editor可以獲取到一個文件輸出流再將其寫入到文件系統(tǒng)上狮崩。
通過editor.commit()來進(jìn)行提交递雀,如果發(fā)生異常則調(diào)用abort()來回退整個操作瓦戚。
DiskLruCache的緩存查找
查找過程也是需要將url轉(zhuǎn)化為key值通過DiskLruCache的get方法獲取到Snapshot對象蛔钙,通過它可以得到緩存圖片的文件輸出流 有了它就可以獲取到bitmap對象了