生活随笔
收集整理的這篇文章主要介紹了
高效使用Bitmaps(一) 大Bitmap的加载
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
轉(zhuǎn)自:http://my.oschina.net/rengwuxian/blog/182885
高效使用Bitmaps有什么好處?
我 們常常提到的“Android程序優(yōu)化”,通常指的是性能和內(nèi)存的優(yōu)化,即:更快的響應(yīng)速度,更低的內(nèi)存占用。Android程序的性能和內(nèi)存問題,大部 分都和圖片緊密相關(guān),而圖片的加載在很多情況下很用到Bitmap(位圖)這個(gè)類。而由于Bitmap自身的特性(將每個(gè)像素的屬性全部保存在內(nèi)存中), 導(dǎo)致稍有不慎就會(huì)創(chuàng)建出一個(gè)占用內(nèi)存非常大的Bitmap對(duì)象,從而導(dǎo)致加載過慢,還會(huì)有內(nèi)存溢出的風(fēng)險(xiǎn)。所以,Android程序要做優(yōu) 化,Bitmap的優(yōu)化是必不可少的一步。
需要對(duì)Bitmap進(jìn)行優(yōu)化的情形
首先請(qǐng)看一行代碼:
| 1 | mImageView.setImageResource(R.drawable.my_image); |
這是一行從資源文件中加載圖片到ImageView的代碼。通常這段代碼沒什么問 題,但有些情況下,你需要對(duì)這段代碼進(jìn)行優(yōu)化。例如當(dāng)圖片的尺寸遠(yuǎn)遠(yuǎn)大于ImageView的尺寸時(shí),或者當(dāng)你要在一個(gè)ListView或 GridView中批量加載一些大小未知的圖片時(shí)。實(shí)際上,以上這行代碼會(huì)在運(yùn)行時(shí)使用BitmapFactory.decodeStream()方法將 資源圖片生成一個(gè)Bitmap,然后由這個(gè)Bitmap生成一個(gè)Drawable,最后再將這個(gè)Drawable設(shè)置到ImageView。由于在過程中 生成了Bitmap,因此如果你使用的圖片過大,就會(huì)導(dǎo)致性能和內(nèi)存占用的問題。另外,需要優(yōu)化的情形不止這一種,這里就不再列舉。
下面分步說明使用代碼來減小Bitmap的尺寸從而達(dá)到減小內(nèi)存占用的方法:
1. 獲取原圖片尺寸
通常,我們使用BitmapFactory.decodeResource()方法來從資源文件中讀取一張 圖片并生成一個(gè)Bitmap。但如果使用一個(gè)BitmapFactory.Options對(duì)象,并把該對(duì)象的inJustDecodeBounds屬性設(shè) 置為true,decodeResource()方法就不會(huì)生成Bitmap對(duì)象,而僅僅是讀取該圖片的尺寸和類型信息:
?
?
| 1 | BitmapFactory.Options options = new BitmapFactory.Options(); |
| 2 | options.inJustDecodeBounds = true; |
| 3 | BitmapFactory.decodeResource(getResources(), R.id.myimage, options); |
| 4 | int imageHeight = options.outHeight; |
| 5 | int imageWidth = options.outWidth; |
| 6 | String imageType = options.outMimeType; |
2. 根據(jù)原圖尺寸和目標(biāo)區(qū)域的尺寸計(jì)算出合適的Bitmap尺寸
BitmapFactory.Options類有一個(gè)參數(shù) inSampleSize,該參數(shù)為int型,他的值指示了在解析圖片為Bitmap時(shí)在長(zhǎng)寬兩個(gè)方向上像素縮小的倍數(shù)。inSampleSize的默認(rèn) 值和最小值為1(當(dāng)小于1時(shí),解碼器將該值當(dāng)做1來處理),且在大于1時(shí),該值只能為2的冪(當(dāng)不為2的冪時(shí),解碼器會(huì)取與該值最接近的2的冪)。例如, 當(dāng)inSampleSize為2時(shí),一個(gè)2000*1000的圖片,將被縮小為1000*500,相應(yīng)地,它的像素?cái)?shù)和內(nèi)存占用都被縮小為了原來的 1/4:
| 01 | public static int calculateInSampleSize( |
| 02 | ????????????BitmapFactory.Options options, int reqWidth, int reqHeight) { |
| 04 | ????final int height = options.outHeight; |
| 05 | ????final int width = options.outWidth; |
| 06 | ????int inSampleSize = 1; |
| 08 | ????if (height > reqHeight || width > reqWidth) { |
| 10 | ????????final int halfHeight = height / 2; |
| 11 | ????????final int halfWidth = width / 2; |
| 13 | ????????// 在保證解析出的bitmap寬高分別大于目標(biāo)尺寸寬高的前提下,取可能的inSampleSize的最大值 |
| 14 | ????????while ((halfHeight / inSampleSize) > reqHeight |
| 15 | ????????????????&& (halfWidth / inSampleSize) > reqWidth) { |
| 16 | ????????????inSampleSize *= 2; |
| 20 | ????return inSampleSize; |
3. 根據(jù)計(jì)算出的inSampleSize生成Bitmap?
| 01 | public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, |
| 02 | ????????int reqWidth, int reqHeight) { |
| 04 | ????// 首先設(shè)置 inJustDecodeBounds=true 來獲取圖片尺寸 |
| 05 | ????final BitmapFactory.Options options = new BitmapFactory.Options(); |
| 06 | ????options.inJustDecodeBounds = true; |
| 07 | ????BitmapFactory.decodeResource(res, resId, options); |
| 09 | ????// 計(jì)算 inSampleSize 的值 |
| 10 | ????options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); |
| 12 | ????// 根據(jù)計(jì)算出的 inSampleSize 來解碼圖片生成Bitmap |
| 13 | ????options.inJustDecodeBounds = false; |
| 14 | ????return BitmapFactory.decodeResource(res, resId, options); |
這里有一點(diǎn)要注意,就是要在第二遍decode之前把inJustDecodeBounds設(shè)置回false。
4. 調(diào)用以上的decodeSampledBitmapFromResource方法,使用自定尺寸的Bitmap。
如果你要將一張大圖設(shè)置為一個(gè)100*100的縮略圖,執(zhí)行以下代碼:
| 1 | mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100)); |
到此,使用decodeResource()方法將一個(gè)大圖解析為小尺寸bitmap的應(yīng)用就完成了。同理,還可以使用decodeStream(),decodeFile()等方法做相同的事,原理是一樣的。
延伸:一個(gè)Bitmap到底占用多大內(nèi)存?系統(tǒng)給每個(gè)應(yīng)用程序分配多大內(nèi)存?
· Bitmap占用的內(nèi)存為:像素總數(shù) * 每個(gè)像素占用的內(nèi)存。在Android中,Bitmap有四種像素類型:ARGB_8888、ARGB_4444、ARGB_565、ALPHA_8,他 們每個(gè)像素占用的字節(jié)數(shù)分別為4、2、2、1。因此,一個(gè)2000*1000的ARGB_8888類型的Bitmap占用的內(nèi)存為 2000*1000*4=8000000B=8MB。
· Android根據(jù)設(shè)備屏幕尺寸和dpi的不同,給系統(tǒng)分配的單應(yīng)用程序內(nèi)存大小也不同,具體如下表(表格取自Android 4.4 Compatibility Definition Document (CDD)):
?
?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??
| ?屏幕尺寸 | ?DPI | ?應(yīng)用內(nèi)存 |
| ?small / normal / large | ?ldpi / mdpi | ?16MB |
| ?small / normal / large | ?tvdpi / hdpi | ?32MB |
| ?small / normal / large | ?xhdpi | ?64MB |
| ?small / normal / large | ?400dpi | ?96MB |
| ?small / normal / large | ?xxhdpi | ?128MB |
| ?xlarge | ?mdpi | ?32MB |
| ?xlarge | ?tvdpi / hdpi | ?64MB |
| ?xlarge | ?xhdpi | ?128MB |
| ?xlarge | ?400dpi | ?192MB |
| ?xlarge | ?xxhdpi | ?256MB |
總結(jié)
以上是生活随笔為你收集整理的高效使用Bitmaps(一) 大Bitmap的加载的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。