徹底解決Android 拍照 內存溢出 Out of Memory的問題

內存溢出相信做過編程的人都知道一二,這裏說Android 內存溢出的問題:、問題描述:Android下的相機在獨自使用時,拍照沒有問題,通過我們的代碼調用時,也正常,但是更換了不同廠商的平板,ROM由Android4.0變成了Android4.1後,拍照出現了OutOfMemory異常,程序中斷退出。如何解決這個問題呢?
二、先看看我們之前所寫的代碼
1) 調用系統相機(沒有懷疑這裏出錯,代碼略)
2)顯示圖片
mImageView = (ImageView) findViewById(R.id.imageView);
fileName = mData.get(0).toString();
Bitmap bitmap = BitmapFactory.decodeFile(fileName);
mImageView.setImageBitmap(bitmap);
三、問題分析
經過調試排查,發現我們的bitmap圖片達到3M,如果是3K則不出錯。啥原理呢?
四、先來看看,Android的內存溢出是如何發生的?
Android的虛擬機是基於寄存器的Dalvik,它的最大堆大小一般是16M,有的機器爲24M。因此我們所能利用的內存空間是有限的。如果我們的內存佔用超過了一定的水平就會出現OutOfMemory的錯誤。
爲什麼會出現內存不夠用的情況呢?我想原因主要有兩個:
程序本身運行就佔有一定的內存,而程序在使用較大的bitmap時,又需要一個更大的內存空間。控制不當,就容易造成內OutOfMemory。
五、Android對應用程序內存的限制
android不同設備單個進程可用內存是不一樣的,可以查看/system/build.prop文件。
dalvik.vm.heapsize=24m
dalvik.vm.heapgrowthlimit=16m
可以自行對這個限制進行更改,當然需要先對設備進行ROOT
六、加載位圖原理分析
1、BitmapFactory提供了幾種解碼方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便從多種資源中創建一個Bitmap(位圖)對象。可以根據你的圖片數據來源選擇最合適的解碼方式。這些方法視圖爲構造Bitmap對象分配內存,因此很容易導致OutOfMemory(OOM)異常。每一種解碼方式都有額外的特徵,你可以通過BitmapFactory.Options類類指定解碼方法。
2、儘量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource直接使用圖片路徑來設置一張大圖,因爲這些函數在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多內存。改用先通過BitmapFactory.decodeStream方法,創建出一個bitmap,再調用上述方法將其設爲ImageView的 source。decodeStream最大的祕密在於其直接調用JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,從而節省了java層的空間。下面是使用InputStream加載圖片的幾種方法:
方法一、加載資源文件中指定的圖片
InputStream is = getResources().openRawResource(R.drawable.temp);
方法二、加載assest目錄下的圖片
AssetManager asm=getAssetMg();
InputStream is=asm.open(name);//name:圖片的名稱
方法三、加載SD卡目錄下的圖片
String path =Environment.getExternalStorageDirectory().toString()+ "/DCIM/device.png";
inputStream is = new FileInputStream(path)
七、解決方案
private ImageView preview;
//1.加載位圖
String path = Environment.getExternalStorageDirectory().toString()+"/DCIM/device.png";
inputStream is = new FileInputStream(path)
//2.爲位圖設置100K的緩存
BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inTempStorage = new byte[100 * 1024];
//3.設置位圖顏色顯示優化方式
//ALPHA_8:每個像素佔用1byte內存(8位)
//ARGB_4444:每個像素佔用2byte內存(16位)
//ARGB_8888:每個像素佔用4byte內存(32位)
//RGB_565:每個像素佔用2byte內存(16位)
//Android默認的顏色模式爲ARGB_8888,這個顏色模式色彩最細膩,顯示質量最高。但同樣的,佔用的內存//也最大。也就意味着一個像素點佔用4個字節的內存。我們來做一個簡單的計算題:3200*2400*4 bytes //=30M。如此驚人的數字!哪怕生命週期超不過10s,Android也不會答應的。
opts.inPreferredConfig = Bitmap.Config.RGB_565;
//4.設置圖片可以被回收,創建Bitmap用於存儲Pixel的內存空間在系統內存不足時可以被回收
opts.inPurgeable = true;
//5.設置位圖縮放比例
//width,hight設爲原來的四分一(該參數請使用2的整數倍),這也減小了位圖佔用的內存大小;例如,一張//分辨率爲2048*1536px的圖像使用inSampleSize值爲4的設置來解碼,產生的Bitmap大小約爲//512*384px。相較於完整圖片佔用12M的內存,這種方式只需0.75M內存(假設Bitmap配置爲//ARGB_8888)。
opts.inSampleSize = 4;
//6.設置解碼位圖的尺寸信息
opts.inInputShareable = true; 
//7.解碼位圖
Bitmap btp =BitmapFactory.decodeStream(is,null, opts);    
//8.顯示位圖
preview.setImageBitmap(bitmap);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章