在android開發過程中圖片的存儲優化是非常常見,處理不好,時常會造成圖片OOM。接下來分享一下我在開發過程中做的相應的處理,僅供各位參考,如有不足還請多多指教。
首先我們知道圖片在app存在形式無非就是:file、stream流、bitmap!
一、接下來列出幾個圖片OOM的出現情況
1、在一個頁面中一次性加載過多的圖片
2、加載的圖片過大
3、bitmap的錯誤使用
二、圖片優化的處理方式:尺寸壓縮、質量壓縮、內存複用
在此我們先知道一張圖片的大小=圖片的寬x圖片的高x一個像素所佔的大小。
1、尺寸壓縮
按照一定的比例減小圖片的寬高從而減少單位尺寸的像素值,這樣的話可以改變圖片在內存中的大小。這種做法只是改變了圖片在加載時內存中的大小,但是磁盤中圖片的大小是沒有發生變化的。
代碼示例:
/**
* @param pathUrl 文件路徑
* @return
*/
public Bitmap getBitmap(String pathUrl) {
// 配置壓縮的參數
BitmapFactory.Options options = new BitmapFactory.Options();
// 開始讀入圖片,此時把options.inJustDecodeBounds 設爲true,方便圖片在不加載進內存的情況下獲取圖片的寬高
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(pathUrl, options);//這個時候decode的bitmap爲null
options.inJustDecodeBounds = false;//將inJustDecodeBounds設置爲false,加載圖片數據
//nSampleSize的作用就是可以把圖片的寬和高縮小inSampleSize倍,所佔內存縮小inSampleSize的平方
//例如,inSampleSize = 2,則取出的縮略圖的寬和高都是原始圖片的1/2,圖片大小就爲原始大小的1/4。
options.inSampleSize = calculateInSampleSize(options,400,100);
bitmap = BitmapFactory.decodeFile(pathUrl, options);//重新讀出圖片
return bitmap;
}
/**
* @param options
* @param reqWidth 我們期望的圖片的寬,單位px
* @param reqHeight 我們期望的圖片的高,單位px
* @return
*/
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
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;
}
1、質量壓縮
質量壓縮不會減少圖片的像素,它是在保持像素的前提下改變圖片的位深及透明度,來達到壓縮圖片的目的,圖片的長,寬,像素都不會改變,它只是改變磁盤中的文件大小,並不能改變加載時內存中的圖片大小。
代碼示例:
/** * @param bitmap bitmap * @param int quality * @return */ public Bitmap qualityBitmap(Bitmap bitmap, int quality){ //quality,可以調節你壓縮的比例,但是質量壓縮對png格式這種圖片沒有作用,因爲png是無損壓縮。 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.WEBP,100,outputStream); while (outputStream.toByteArray().length/1024>quality){ outputStream.reset(); bitmap.compress(Bitmap.CompressFormat.WEBP,quality,outputStream); if (quality>5)quality-=5; else break; } ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig=Bitmap.Config.RGB_565; Bitmap bitmap1 = BitmapFactory.decodeStream(inputStream, null, options); return bitmap1; }
3、內存複用inbitmap注意點
2.3上,bitmap的數據是存儲在native的內存區域,並不是在Dalvik的內存堆上。
3.0開始,系統在BitmapFactory.Options裏引入了inBitmap機制來配合緩存機制。如果在載入圖片時傳入了inBitmap那麼載入的圖片就是inBitmap裏的值。這樣可以統一有緩存和無緩存的載入方式。
使用inBitmap,在4.4之前,只能重用相同大小的bitmap的內存區域,而4.4之後你可以重用任何bitmap的內存區域,只要這塊內存比將要分配內存的bitmap大就可以。
新申請的bitmap與舊的bitmap必須有相同的解碼格式
使用此方法需要inMutable=true,inSampleSize=1
*例外,bitmap也可以通過縮放法壓縮(martix)、createScaledBitmap。
以上是別人在項目過程中對圖片處理一些做法,寫的不錯,請多多指教