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