Android圖片壓縮及內存緩存

Android圖片壓縮

圖片BitmapFactory壓縮


Android中提供的對圖像的解析BitmapFactory類。直接上代碼,以作爲記錄.


/**
     * 根據普通需要顯示的寬和高進行壓縮
     * 
     * @param path
     * @param width
     * @param height
     * @return
     */
    protected Bitmap decodeSampledBitmapFromPath(String path, int width,
            int height) {
        // 獲取圖片的寬和高,並不把圖片加載到內存當中
        BitmapFactory.Options options = new BitmapFactory.Options();
        // true表示禁止系統加載圖像到內存
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeFile(path, options);
        options.inSampleSize = caculateInSampleSize(options, width, height);

        // 使用獲取到的inSampleSize再次解析圖片
        options.inJustDecodeBounds = false;

        Bitmap bitmap = BitmapFactory.decodeFile(path, options);

        return bitmap;
    }

    /**
     * 根據需求的寬和高以及實際的寬和高計算SampleSize
     * 
     * @param options
     * @param width
     * @param height
     * @return
     */
    private int caculateInSampleSize(Options options, int reqWidth,
            int reqHeight) {
        int width = options.outWidth;
        int height = options.outHeight;

        int inSampleSize = 1;
        // 得到一個比例
        if (width > reqWidth || height > reqHeight) {
            int widthRadio = Math.round(width * 1.0f / reqWidth);
            int heightRadio = Math.round(height * 1.0f / reqHeight);

            inSampleSize = Math.max(widthRadio, heightRadio);
        }
        return inSampleSize;
    }

圖片緩存LruCache


在過去,我們經常會使用一種非常流行的內存緩存技術的實現,即軟引用或弱引用 (SoftReference or WeakReference)。但是現在已經不再推薦使用這種方式了,因爲從 Android 2.3 (API Level 9)開始,垃圾回收器會更傾向於回收持有軟引用或弱引用的對象,這讓軟引用和弱引用變得不再可靠。下面是使用LruCache的例子

private LruCache<String, Bitmap> mMemoryCache;  

@Override  
protected void onCreate(Bundle savedInstanceState) {  
    // 獲取到可用內存的最大值,使用內存超出這個值會引起OutOfMemory異常。  
    // LruCache通過構造函數傳入緩存值,以KB爲單位。  
    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  
    // 使用最大可用內存值的1/8作爲緩存的大小。  
    int cacheSize = maxMemory / 8;  
    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {  
        @Override  
        protected int sizeOf(String key, Bitmap bitmap) {  
            // 重寫此方法來衡量每張圖片的大小,默認返回圖片數量。  
            return value.getRowBytes() * value.getHeight();  
        }  
    };  
}  

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  
    if (getBitmapFromMemCache(key) == null) {  
        mMemoryCache.put(key, bitmap);  
    }  
}  

public Bitmap getBitmapFromMemCache(String key) {  
    return mMemoryCache.get(key);  
}

在中高配置的手機當中,這大概會有4兆(32/8)的緩存空間。一個全屏幕的 GridView 使用4張 800x480分辨率的圖片來填充,則大概會佔用1.5兆的空間(800*480*4)。因此,這個緩存大小可以存儲2.5頁的圖片。

當向 ImageView 中加載一張圖片時,首先會在 LruCache 的緩存中進行檢查。如果找到了相應的鍵值,則會立刻更新ImageView ,否則開啓一個後臺線程來加載這張圖片。

public void loadBitmap(int resId, ImageView imageView) {  
    final String imageKey = String.valueOf(resId);  
    final Bitmap bitmap = getBitmapFromMemCache(imageKey);  
    if (bitmap != null) {  
        imageView.setImageBitmap(bitmap);  
    } else {  
        imageView.setImageResource(R.drawable.image_placeholder);  
        BitmapWorkerTask task = new BitmapWorkerTask(imageView);  
        task.execute(resId);  
    }  
} 

BitmapWorkerTask 還要把新加載的圖片的鍵值對放到緩存中。

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {  
    // 在後臺加載圖片。  
    @Override  
    protected Bitmap doInBackground(Integer... params) {  
        final Bitmap bitmap = decodeSampledBitmapFromResource(  
                getResources(), params[0], 100, 100);  
        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);  
        return bitmap;  
    }  
}  

圖片的壓縮及內存緩存這樣的方案,在實戰中經常使用到,而且OOM問題有效的得到解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章