因為手機的內存資源是有限的,每個app可使用的內存是受限的。而現在采用高分辨率拍的照片往往很大。如果加載時不注意方法,很有可能會引起java.lang.OutofMemoryError: bitmap size exceeds VM budget
. 異常而導致app奔潰退出。
另外ImageView支持的圖片大小也是受限制的,比如整個App雖然只放一張圖片,該圖片大小也沒超過整個app的內存上限。但該圖片大小超過了ImageView的最大值,這也是有問題的。這時需要采取方法,在加載圖片時縮小加載圖片的大小。具體的策略看下面的介紹。
在真正創建和加載(需要實際耗費內存)一個圖片對象時,我們可以先獲取圖像的大小信息。這里我們可以用到BitmapFactory.Options這個類。BitmapFactory.Options這個類,有一個字段叫做 inJustDecodeBounds 。SDK中對這個成員的說明是這樣的:
“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.”
也就是說,如果我們把它設為true,那么BitmapFactory.decodeFile(String path, Options opt)並不會真的返回一個Bitmap給你,但它會把它的寬,高等基本信息取回來給你,這樣就不會實際分配圖片所需的內存。代碼例子如下:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.drawable.pic1, options); String text = "imageHeight:" + options.outHeight + ",imageWidth:" + options.outWidth + ",imageType:" + options.outMimeType; Toast.makeText(this, text, Toast.LENGTH_LONG).show();
知道了圖片的大小后,就可以考慮是將整個完整的圖片加載到內存中,或是將縮小版加載到內存中。因為手機屏幕本身大小就那么大,沒必要將原尺寸的圖片加載進去。比如如果屏幕的大小為128x96,則將大小為1024x76的圖片加載進去就沒有意義。
為了告訴解碼器將圖片壓縮后加載到內存中,需要設置BitmapFactory.Options對象的 inSampleSize 屬性。比如,一張2048*1536的圖片,如果設置inSampleSize的值為4. 縮小后圖片的尺寸變為 512x384。占用的內存由原來的12M變為0.75M。下面的方法可以計算出一個圖片應該設置的inSampleSize值:
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // reqWidth、reqHeight是想要顯示圖片的大小,如屏幕的大小或ImageView控件的大小 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; }
有了適當的inSampleSize值后,就可以真正的執行加載圖片的操作了。代碼如下:
final BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeResource(res, resId, options); ImageView imageView = (ImageView)findViewById(R.id.imageView1); imageView.setImageBitmap(bitmap);
實際上對於大的圖片,通過使用inSampleSize將圖片變小后加載到內存中,只要不是變了非常小,不會影響視覺效果。但來的好處是顯而意見的,會大大降低對內存的使用。一般對於大尺寸的照片(如用手機自身拍的),將inSampleSize設置為4一般不會影響視覺效果。