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

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