注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
圖像的的形狀和尺寸千變萬化。在很多情況下它們比一般的應用UI所需要的尺寸更大一些。例如,在系統圖庫這個應用中,顯示的照片是用你的Android設備拍攝的照片,它們比起屏幕的尺寸來說要大多了。
假設你現在只有有限的內存,那么在理想情況下你希望在內存中加載分辨率更小的圖片。這個低分辨率版本的圖片需要和將它顯示出來的UI組件的尺寸相匹配。一個過高分辨率的圖片并不會帶來什么改善視覺體驗,反而會消耗大量的內存空間,并且因為在運行時需要調整圖片的尺度而導致應用性能表現欠佳。
這節課將帶你學習通過加載一個大位圖的減采樣版本的圖片到內存中,以此來防止應用的內存空間耗盡。
一). 讀取位圖的尺寸和類型
BitmapFactory
類提供了一些解碼方法(
decodeByteArray()
,
decodeFile()
,
decodeResource()
等)來為不同的源創建位圖。應該基于你的圖像數據源選擇最合適的解碼方法。這些方法嘗試為構建好的圖像分配空間,因此它很容易導致
OutOfMemory
異常。每種解碼方法都有額外的參數選項可以讓你通過
BitmapFactory.Options
類指定解碼選項。在解碼時,將
inJustDecodeBounds
屬性設置為
true
可以防止內存溢出,如果不設置
outWidth
,
outHeight
和
outMimeType
的話,那么就會對該圖像對象返回
null
。這個技術逼迫你在構造(和分配內存時)之前先讀取圖像的尺寸和圖像數據的類型。
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true ; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
為了避免 OutOfMemory 異常,在解碼圖像之前檢查它的尺寸,除非你完全相信提供給你圖像的源會給你尺寸正好合適的圖像數據,它能夠符合有限的存儲空間。
二). 加載一個縮小版本的圖像到存儲當中
現在這個圖像的尺寸已經知道了,它們可以被用來這個完整的圖片能否被加載到內存中,或者一個減采樣的版本是否要被加載。下面是一些要考慮的因素:
- 估計一下如果加載完整圖片的話內存的使用情況。
- 結合應用中其他內存的需求,決定這幅圖片能使用多少大的內存空間。
- 這個圖片要被加載到的 ImageView 或UI組建的尺寸。
- 當前設備的屏幕尺寸和分辨率。
例如,如果要把一幅 1024x768的 圖片加載到一個大小為128x96大小的 ImageView ,顯然這么做事不值得的。
為了告訴解碼器對圖像進行減采樣,加載一個更小的版本到內存中,在你的 BitmapFactory.Options 對象中將 inSampleSize 設置為 true 。例如,一個分辨率為 2048x1536的 圖像加上 inSampleSize 設置為4的選項后,會產生一幅大小為 512x384的圖。將它加載進系統需要使用0.75MB而不是全尺寸圖像所需要的12MB(假定位圖配置為 ARGB_8888 )。下面的方法用來計算一個圖像的減采樣版本(如果圖像過大的話):
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 ; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2 ; } } return inSampleSize; }
Note:
從上述代碼可以看到,在計算減采樣因數時,以2為級數增加, 選擇以2為級數的原因是解碼器在減采樣時也是選擇以2為級數時最接近的那個數字做減采樣的,具體的闡述可以查看: inSampleSize 的文檔
為了用這個方法,首先在解碼時,將 inJustDecodeBounds 設置為 true ,將選項傳遞進去然后再使用新的 inSampleSize 值解碼,并把 inJustDecodeBounds 設置為 false 。
public static Bitmap decodeSampledBitmapFromResource(Resources 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 inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false ; return BitmapFactory.decodeResource(res, resId, options); }
這個方法使得將任意大尺寸的圖片加載到值顯示100x100大小的 ImageView 中時,非常方便,就像下面代碼所顯示的那樣:
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage,
100, 100));
你也可以通過替換適當的 BitmapFactory.decode* 方法(如果需要的話),對來自其他源的照片做類似的處理過程。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
