首先解析一下基本的知識: javascript
位圖模式,bitmap顏色位數是1位
java
灰度模式,bitmap顏色位數是8位,和256色同樣 android
RGB模式,bitmap顏色位數是24位 在RGB模式下,一個像素對應的是紅、綠、藍三個字節 算法
CMYK模式,bitmap顏色位數是32位 在CMYK模式下,一個像素對應的是青、品、黃、黑四個字節 app
圖像文件的字節數(Byte) = 圖像分辨率*顏色深度/8(bit/8) 函數
例如:一幅640*480圖像分辨率、RGB色通常爲24位真彩色,圖像未經壓縮的數據容量爲:640X480X24/8=921600字節=900KB(1KB=l千字節=1024字節)。
注:一個圖像文件佔的磁盤空間大小還和磁盤的文件格式有關。如:NTFS最小單位爲4KB 因此圖像文件大小確定是4KB的倍數。可是有圖圖片壓縮算法的存在,圖片文件在保存時,體積要比在內存的大小小得多,如640x480的圖片文件大小通常只在200K~300K。這也是爲何,加載幾MB的圖片文件,會致使JVM內存溢出,致使OutofMemoryException的緣由。 google
由上面的公式,咱們能夠得出,加載的圖片所佔的內存大小,取決於其分辨率和顏色數。 spa
咱們再來看看Google官方的介紹: .net
這個已經很是的明白了,咱們VM的app進程所得到的內存只有區區的16MB,普普統統的5MP攝像頭拍出來的圖片,直接加載,將佔用接近19MB的內存。可見,不進行壓縮,內存將會直接溢出。 code
再瞭解一下,android讀取解析圖片的方式,基本與Java的方式類型,經過文件輸入流,而後進行解碼,再轉成圖片格式;
固然google的android也爲咱們封裝好了若干方法,來方便快捷地完成這項工做,如ImageView的setImageBitmap,setImageResource,BitmapFactory的decodeResource等,可是儘可能不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource來設置一張大圖,由於這些函數在完成decode後,最終都是經過java層的createBitmap來完成的,須要消耗更多內存;
所以,改用先經過BitmapFactory.decodeStream方法,建立出一個bitmap,再將其設爲ImageView的source,加載顯示。decodeStream最大的祕密在於其直接調用JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,從而節省了java層的空間。
在使用
decodeStream
讀取圖片時,再加上Config參數,就能夠更有效地控制加載目標的內存大小,從而更有效阻止拋
OutofMemoryException異常,下面用一段代碼說明:
- public static Bitmap readBitmapAutoSize(String filePath, int outWidth, int outHeight) {
- //outWidth和outHeight是目標圖片的最大寬度和高度,用做限制
- FileInputStream fs = null;
- BufferedInputStream bs = null;
- try {
- fs = new FileInputStream(filePath);
- bs = new BufferedInputStream(fs);
- BitmapFactory.Options options = setBitmapOption(filePath, outWidth, outHeight);
- return BitmapFactory.decodeStream(bs, null, options);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- bs.close();
- fs.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- private static BitmapFactory.Options setBitmapOption(String file, int width, int height) {
- BitmapFactory.Options opt = new BitmapFactory.Options();
- opt.inJustDecodeBounds = true;
- //設置只是解碼圖片的邊距,此操做目的是度量圖片的實際寬度和高度
- BitmapFactory.decodeFile(file, opt);
-
- int outWidth = opt.outWidth; //得到圖片的實際高和寬
- int outHeight = opt.outHeight;
- opt.inDither = false;
- opt.inPreferredConfig = Bitmap.Config.RGB_565;
- //設置加載圖片的顏色數爲16bit,默認是RGB_8888,表示24bit顏色和透明通道,但通常用不上
- opt.inSampleSize = 1;
- //設置縮放比,1表示原比例,2表示原來的四分之一....
- //計算縮放比
- if (outWidth != 0 && outHeight != 0 && width != 0 && height != 0) {
- int sampleSize = (outWidth / width + outHeight / height) / 2;
- opt.inSampleSize = sampleSize;
- }
-
- opt.inJustDecodeBounds = false;//最後把標誌復原
- return opt;
- }
另外,decodeStream直接拿的圖片來讀取字節碼了, 不會根據機器的各類分辨率來自動適應, 使用了decodeStream以後,須要在hdpi和mdpi,ldpi中配置相應的圖片資源, 不然在不一樣分辨率機器上都是一樣大小(像素點數量),顯示出來的大小就不對了。 可參考下面的代碼:
- BitmapFactory.Options opts = new BitmapFactory.Options();
- //設置圖片的DPI爲當前手機的屏幕dpi
- opts.inTargetDensity = ctx.getResources().getDisplayMetrics().densityDpi;
- opts.inScaled = true;
另外,圖片的bitmap對象爲大對象,不用了要注意主動回收,
- if(!bmp.isRecycle() ){
- bmp.recycle() //回收圖片所佔的內存
- system.gc() //提醒系統及時回收