前幾天作項目的時候,甲方要求是PAD (SAMSUNG P600 10.1寸 2560*1600)的PAD上顯示高分辨率的大圖片。java
SQLITE採用BOLD方式存儲圖片,這個存取過程就不說了哈,網上一大堆。數據庫
但是在加載/讀取/顯示圖片的時候會報OOM錯誤,上網查了很是多解決方式還繞了很是多彎路,最後仍是找到了緣由所在。如下從幾個方面來解釋一下OOM問題的解決方式。函數
(謝謝周同窗的「尺寸」提醒。否則我可能一生都要矇在鼓裏)spa
1.Android APP內存.net
作一個APP開發的時候,仍是不要想着去擴大Android系統賦予的內存上限了。部分老機型老系統16M。大部分都是24M了。code
一些大型遊戲用dalvik.system.VMRuntime來干涉GC過程(這個類我尚未學過。blog
。遊戲
。剛據說不久)。圖片
聽說用NDK開發時候,C可以動態申請多餘的內存空間,但是我沒用過NDK,從此也不打算用了(我的緣由)。內存
2.圖片文件大小
甲方給了一大堆文件大小不一的圖片,在加載數據庫->讀取出來->顯示出來的這個過程當中,出現了很是多OOM,分爲:
a.加載圖片時使用ByteArrayStream建立流,size爲Height * Width * 4。OOM;
b.讀取圖片時候OOM,同上;
c.顯示圖片時候OOM,decodeResource函數報錯,OOM;
開始時候覺得是文件大小問題。後來發現有些2M的圖片都能顯示,但是某些1M的圖片確報錯。因此在必定範圍內,可以證實。圖片OOM問題與文件大小無關。
3.圖片尺寸(分辨率)
調查這些能顯示的圖片和不能顯示的圖片的不一樣。發現長寬差距很是大。那些能成功顯示的圖片爲1005*1500大小,而其它圖片都是3000*5000以上。
我用PAINT(一款適合小白的圖像處理軟件。儘管不如PS但是功能已經很強大了,最新版需要安裝NET 4.5)壓縮了圖片大小。壓縮到1005*1500。顯示成功。
4.函數調用
閱讀了這位大神的博客:
http://blog.csdn.net/huangbiao86/article/details/8072128
摘取當中最精華的部分吧:
儘可能不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource來設置一張大圖,因爲這些函數在完畢decode後。終於都是經過java層的createBitmap來完畢的。需要消耗不少其它內存。
所以,改用先經過BitmapFactory.decodeStream方法,建立出一個bitmap,再將其設爲ImageView的 source,decodeStream最大的祕密在於其直接調用JNI>>nativeDecodeAsset()來完畢decode。無需再使用java層的createBitmap,從而節省了java層的空間。
假設在讀取時加上圖片的Config參數,可以跟有效下降載入的內存。從而跟有效阻止拋out of Memory異常
另外。decodeStream直接拿的圖片來讀取字節碼了。 不會依據機器的各類分辨率來本身主動適應, 使用了decodeStream以後,需要在hdpi和mdpi,ldpi中配置對應的圖片資源, 不然在不一樣分辨率機器上都是相同大小(像素點數量),顯示出來的大小就不正確了。
看來讀底層源代碼仍是很是實用的,setImageBitmap 和 setImageResource 和 decodeResource在運行過程當中仍是調用了createBitmap來建立一個新的bitmap。建立bitmap會加重內存消耗,因此不推薦使用了。應該使用decodeStream方法。
圖片的壓縮過程也可以設置一個合適的百分比來控制大小。
多張圖片的使用中,請注意流的flush與close(我沒有及時flush和close的時候也執行正確了,這個有待研究一下,但是爲了保證一個良好的習慣仍是注意下吧)。
5.關於options方法
網上還有很是多文章用BitmapFactory.Options來做爲decodeStream時候的一個參數,這個我臨時沒有詳細實驗過,哪位朋友實驗過了可以回覆交流哈