1. 程式人生 > >解決Android呼叫系統相機連續拍照出現的記憶體溢位問題

解決Android呼叫系統相機連續拍照出現的記憶體溢位問題

記憶體溢位相信做過程式設計的人都知道一二,這裡說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);