對於大尺寸圖片加載,如何正常加載顯示且不發生OOM?
- 圖片採樣,應用場景:圖片全部顯示在控件上
- 圖片按區域加載,應用場景:高清巨圖,不允許壓縮,如世界地圖、清明上河圖
圖片採樣
圖片採樣的方法,是根據需要顯示圖片控件的大小對圖片進行壓縮顯示。
主要用法
1、根據控件的寬高與原圖的寬高的比例,計算出BitmapFactory.Options
中inSampleSize
值。例如:
public static int calculateInSampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options) {
if (reqHeight == 0 || reqWidth == 0) {
return 1;
}
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;
}
}
Log.d(“TAG”, "calculateInSampleSize: " + inSampleSize);
return inSampleSize;
}
第一、二個參數分別是顯示控件的寬度和高度,第三個參數是設置了inSampleSize的BitmapFactory.Options對象,設置inSampleSize爲2的冪是因爲解碼器最終會對非2的冪的數進行向下處理,獲取到最靠近2的冪的數。詳情參考inSampleSize的文檔。
2、然後在解析圖片文件時,傳入這個BitmapFactory.Options
。例如
public static Bitmap getFitSampleBitmap(String filePath, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
//計算inSampleSize方法
options.inSampleSize = calculateInSampleSize(width, height, options);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
第一個參數是圖片存放的路徑,第二、三個參數是顯示控件的寬度和高度
測試過程,查看Memory使用情況
1、沒有壓縮處理,內存佔用106M左右
2、inSampleSize=2,內部佔用46M左右
從上面對比可以看出,經過圖片的採樣壓縮,內存使用大大降低,減少OOM的發生。
具體Demo可以參考Android 多種方式正確的加載圖像,有效避免oom
圖片按區域加載
對於世界地圖等高清巨圖,如果不壓縮,那麼按照原圖尺寸加載,屏幕肯定不夠,並且考慮內存的情況,不可能一次性將整圖加載到內存中,否則很容易發生OOM。如何解決這種問題,可以採用的方法:局部加載,讓圖片按區域加載,用到Android提供的類:
BitmapRegionDecoder
主要用法:
1、創建BitmapRegionDecoder
對象
BitmapRegionDecoder
提供了一系列的newInstance方法來構造對象,傳入需要處理的圖片,支持傳入文件路徑,文件描述符,文件的inputstrem等。
例如:
BitmapRegionDecoder bitmapRegionDecoder =
BitmapRegionDecoder.newInstance(inputStream, false);
2、顯示指定的區域
bitmapRegionDecoder.decodeRegion(rect, options);
參數一是一個rect,指定顯示的區域,參數二是BitmapFactory.Options,可以控制圖片的inSampleSize
, inPreferredConfig
等。
具體Demo可以學習Android 高清加載巨圖方案 拒絕壓縮圖片,加上手勢移動,動態修改顯示的區域。
調試DEMO時,發現存在一個問題,初始化顯示setInputStream
時,圖片只顯示一角,手勢移動沒有反應。
通過Debug,查到BitmapFactory.Options獲取圖片的寬高有問題,修改方式是直接通過BitmapRegionDecoder.getWidth和getHeight獲取寬高。
參考資料