高效地顯示Bitmap圖片 1 - 有效率地加載大尺寸的位圖
https://blog.csdn.net/kesenhoo/article/details/7489243
Loading Large Bitmaps Efficiently [有效地加載大尺寸位圖]
- 圖片有不同的形狀與大小。在大多數情況下它們的實際大小都比需要呈現出來的要大很多。例如,係統的Gallery程序會顯示那些你使用設備camera拍攝的圖片,但是那些圖片的分辨率通常都比你的設備屏幕分辨率要高很多。
- 考慮到程序是在有限的內存下工作,理想情況是你隻需要在內存中加載一個低分辨率的版本即可。這個低分辨率的版本應該是與你的UI大小所匹配的,這樣才便於顯示。一個高分辨率的圖片不會提供任何可見的好處,卻會占用寶貴的(precious)的內存資源,並且會在快速滑動圖片時導致(incurs)附加的效率問。
- 這一課會介紹如何通過加載一個低版本的圖片到內存中去decoding大的bitmaps,從而避免超出程序的內存限製
Read Bitmap Dimensions and Type [讀取位圖的尺寸與類型]
-
BitmapFactory
類提供了一些decode的方法 (decodeByteArray()
,decodeFile()
,decodeResource()
, etc.) 用來從不同的資源中創建一個Bitmap
. 根據你的圖片數據源來選擇合適的decode方法. 那些方法在構造位圖的時候會嚐試分配內存,因此會容易導致OutOfMemory
的異常。每一種decode方法都提供了通過BitmapFactory.Options
來設置一些附加的標記來指定decode的選項。設置inJustDecodeBounds
屬性為true可以在decoding的時候避免內存的分配,它會返回一個null的bitmap,但是outWidth
,outHeight
與outMimeType
還是可以獲取。這個技術可以允許你在構造bitmap之前優先讀圖片的尺寸與類型。
- 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;
- 為了避免
java.lang.OutOfMemory
的異常,我們在真正decode圖片之前檢查它的尺寸,除非你確定這個數據源提供了準確無誤的圖片且不會導致占用過多的內存。
Load a Scaled Down Version into Memory [加載一個按比例縮小的版本到內存中]
-
通過上麵的步驟我們已經知道了圖片的尺寸,那些數據可以用來決定是應該加載整個圖片到內存中還是加一個縮小的版本。下麵有一些因素需要考慮:
- 評估加載完整圖片所需要耗費的內存。
- 程序在加載這張圖片時會涉及到其他內存需求。
- 呈現這張圖片的組件的尺寸大小。
- 屏幕大小與當前設備的屏幕密度。
- 例如,如果把一個原圖是1024*768 pixel的圖片顯示到ImageView為128*96 pixel的縮略圖就沒有必要把整張圖片都加載到內存中。
- 為了告訴decoder去加載一個低版本的圖片到內存,需要在你的BitmapFactory.Options 中設置
inSampleSize
為true 。
For example, 一個分辨率為2048x1536 的圖片,如果設置inSampleSize
為4,那麼會產出一個大概為512x384的bitmap。加載這張小的圖片僅僅使用大概0.75MB,如果是加載全圖那麼大概要花費12MB(前提都是bitmap的配置是ARGB_8888
). 下麵有一段根據目標圖片大小來計算Sample圖片大小的Sample Code:
- 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) {
- if (width > height) {
- inSampleSize = Math.round((float)height / (float)reqHeight);
- } else {
- inSampleSize = Math.round((float)width / (float)reqWidth);
- }
- }
- return inSampleSize;
- }
-
Note: 設置
inSampleSize
為2對於decoder會更加的有效率,然而,如果你打算把調整過大小的圖片Cache到磁盤上,設置為2也能夠很有效的節省緩存的空間. - 為了使用這個方法,首先需要設置
inJustDecodeBounds
為true
, 把options的值傳遞過來,然後使用inSampleSize
的值並設置inJustDecodeBounds
為false 來重新Decode一遍。
- 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);
- }
- 使用上麵這個方法可以簡單的加載一個任意大小的圖片並顯示為100*100 pixel的縮略圖形式。像下麵演示的一樣:
- mImageView.setImageBitmap(
- decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
- 你可以通過替換合適的
BitmapFactory.decode*
方法來寫一個類似的方法從其他的數據源進行decode bitmap。
最後更新:2017-04-04 07:03:06