Bitmap加載和緩存策略

Bitmap加載

BitmapFactory提供了四類(lèi)方法:decodeFile,decodeResource,decodeStream,decodeByteArray,分別用于支持從文件系統(tǒng),資源,輸入流以及字節(jié)數(shù)組中加載一個(gè)Bitmap對(duì)象。
采用BitmapFactory.Options縮放圖片可以高效加載Bitmap,其inSampleSize參數(shù)即采樣率
獲取采樣率?
1.將BitmapFactory.Options的inJustDecodeBounds參數(shù)設(shè)為true并加載圖片
2.從BitmapFactory.Options中取出圖片的原始寬高信息,他們對(duì)應(yīng)于outWidth和outHeight參數(shù)
3.根據(jù)采樣率的規(guī)則并結(jié)合目標(biāo)View的所需大小計(jì)算出采樣率inSampleSize
4.將BitmapFactory.Options的inJustDecodeBounds參數(shù)設(shè)為false,然后重新加載圖片。

public static Bitmap decodeSamledBitmapFromResource(Resource res,int resId,int reqWidth,int reqHeight) {
    // First decode with inJustDecodeBounds = true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res,resId,options);
    // calculate inSamleSize
    options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res,resId,options);
}

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) {
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;
        while( (halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth ) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

mImageView.setImageBitmap(decodeSamledBitmapFromResource(getResources(),R.id.myimage,100,100));
Android中的緩存策略

當(dāng)程序第一次從網(wǎng)絡(luò)加載圖片后,就將其緩存到存儲(chǔ)設(shè)備上,這樣下次使用這張圖片就不用從網(wǎng)絡(luò)上獲取了,節(jié)省流量;很多時(shí)候?yàn)榱颂岣邞?yīng)用的用戶(hù)體驗(yàn),往往還會(huì)把圖片在內(nèi)存中再緩存一份,這樣應(yīng)該打算從網(wǎng)絡(luò)上請(qǐng)求一張圖片時(shí)程序首先會(huì)從內(nèi)存中去獲取,如果內(nèi)存中沒(méi)有那就從存儲(chǔ)設(shè)備中獲取,如果存儲(chǔ)設(shè)備中也沒(méi)有,那就從網(wǎng)絡(luò)下載這張圖片。
緩存策略主要包含緩存的添加,獲取和刪除這三類(lèi)操作。
緩存算法LRU(Least Recently Used),LRU是近期最少使用算法,核心思想是當(dāng)緩存滿時(shí),會(huì)優(yōu)先淘汰那些近期使用的緩存對(duì)象。LRU算法的緩存有兩種:LruCache和DiskLruCache,Lru用于實(shí)現(xiàn)內(nèi)存緩存,而DiskLruCache實(shí)現(xiàn)存儲(chǔ)設(shè)備緩存。

LruCache

強(qiáng)引用:直接的對(duì)象引用
軟引用:但一個(gè)對(duì)象只有軟引用存在時(shí),系統(tǒng)內(nèi)存不足時(shí)此對(duì)象會(huì)被gc回收
弱引用:當(dāng)一個(gè)對(duì)象只有弱引用存在時(shí),此對(duì)象會(huì)隨時(shí)被gc回收
LruCache是一個(gè)泛型類(lèi),它內(nèi)部采用一個(gè)LinkedHashMap以強(qiáng)引用的方式存儲(chǔ)外界的緩存對(duì)象,其提供了get和put方法來(lái)完成緩存的獲取和添加操作,當(dāng)緩存滿時(shí),LruCache會(huì)移除較早使用的緩存對(duì)象,然后添加新的緩存對(duì)象。LruCache是線程安全的

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String,Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key,Bitmap bitmap) {
        return bitmap.getRowBytes()*bitmap.getHeight() / 1024;
    }
}
//從LruCache中獲取一個(gè)緩存對(duì)象
mMemoryCache.get(key)
//向LruCache中添加一個(gè)緩存對(duì)象
mMemoryCache.put(key,bitmap)
DiskLruCache

磁盤(pán)緩存,通過(guò)將緩存對(duì)象寫(xiě)入文件系統(tǒng),從而實(shí)現(xiàn)緩存的效果。
DiskLruCache的創(chuàng)建過(guò)程

private static final long DISK_CACHE_SIZE = 1024* 1024 * 50;//50MB
File diskCacheDir = getDiskCacheDir(mContext,"bitmap");
if(!diskCacheDir.exists()) {
    diskCachDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);

DiskLruCache的緩存添加
DiskLruCache的緩存添加的操作是通過(guò)Editor完成的,Editor表示一個(gè)緩存對(duì)象的編輯對(duì)象;首先需要獲取圖片url所對(duì)應(yīng)的key,然后根據(jù)key就可以通過(guò)edit()來(lái)獲取Editor對(duì)象,一般采用url的MD5作為key。

private String hashKeyFormUrl(String url) {
    String cacheKey;
    try {
        final MessageDigest mDigest = MessageDigest.getInstance("MD5");
        mDigest.update(url.getBytes());
        cacheKey = bytesToHexString(mDigest.digest());
    } catch(NoSuchAlgorithmException e){
        cacheKey = String.valueOf(url.hashCode());
    }
    return cacheKey;
}

private String bytesToHexString(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for(int i=0;i<bytes.length;i++){
        String hex = Integer.toHexString(0xFF & bytes[i]);
         if(hex.length() == 1) {
            sb.append('0');
         }
        sb.append(hex);
    }
    return sb.toString();
}

//將圖片的url轉(zhuǎn)成key以后,就可以獲取Editor對(duì)象了
String key = hashKeyFormUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if(editor!=null){
    OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
}
ImageLoader實(shí)現(xiàn)

內(nèi)存緩存和磁盤(pán)緩存是ImageLoader的核心,只有當(dāng)這兩級(jí)緩存都不可用時(shí)才需要從網(wǎng)絡(luò)中拉取圖片。
首先嘗試從內(nèi)存緩存中讀取圖片,接著嘗試從磁盤(pán)緩存中讀取圖片,最后從網(wǎng)絡(luò)中拉取圖片。
圖片壓縮
內(nèi)存緩存和磁盤(pán)緩存
選擇線程池和Handler來(lái)提供ImageLoader的并發(fā)能力和訪問(wèn)UI的能力。

《Android開(kāi)發(fā)藝術(shù)探討》Bitmap的加載和Cache

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容