Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 加載圖片oom若干方案小結

android 加載圖片oom若干方案小結

編輯:關於Android編程

眾所周知,每個Android應用程序在運行時都有一定的內存限制,限制大小一般為16MB或24MB(視手機而定)。一般我們可以通過獲取當前線程的可運行內存來判斷,比如系統分給當前運行內存只有16M,而你的圖片就有16M,這肯定會oom的。

相關知識介紹

1.顏色模型

常見的顏色模型有RGB、YUV、CMYK等,在大多數圖像API中采用的都是RGB模型,Android也是如此;另外,在Android中還有包含透明度Alpha的顏色模型,即ARGB。

2.計算機中顏色值的數字化編碼

(1)浮點數編碼:比如float: (1.0, 0.5, 0.75),每個顏色分量各占1個float字段,其中1.0表示該分量的值為全紅或全綠或全藍;

(2)24位的整數編碼:比如24-bit:(255, 128, 196),每個顏色分量各占8位,取值范圍0-255,其中255表示該分量的值為全紅或全綠或全藍;

(3)16位的整數編碼:比如16-bit:(31, 45, 31),第1和第3個顏色分量各占5位,取值范圍0-31,第2個顏色分量占6位,取值范圍0-63;

3.Bitmap在內存中的存儲區域

http://www.7dot9.com/2010/08/android-bitmap%E5%86%85%E5%AD%98%E9%99%90%E5%88%B6/一文中對Android內存限制問題做了一些探討,作者認為Bitmap對象通過棧上的引用來指向堆上的Bitmap對象,而Bitmap對象又對應了一個使用了外部存儲的native圖像,實際上使用的是byte[]來存儲的內存空間。但為了確保外部分配內存成功,應該保證當前已分配的內存加上當前需要分配的內存值,大小不能超過當前堆的最大內存值,而且內存管理上將外部內存完全當成了當前堆的一部分。

4.Java對象的引用類型

(1)強引用(StrongReference)如果一個對象具有強引用,那垃圾回收器絕不會回收它。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足的問題。

(2)軟引用(SoftReference)如果一個對象只具有軟引用,則內存空間足夠,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。

(3)弱引用(WeakReference)弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。

(4)虛引用(PhantomReference)“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。

有了上面的基礎儲備,我們來談談圖片的oom解決方案:

(1)緩存圖像到內存,采用軟引用緩存到內存,而不是在每次使用的時候都從新加載到內存;

(2)調整圖像大小,手機屏幕尺寸有限,分配給圖像的顯示區域本身就更小,有時圖像大小可以做適當調整;

(3)采用低內存占用量的編碼方式,比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省內存;

(4)及時回收圖像,如果引用了大量Bitmap對象,而應用又不需要同時顯示所有圖片,可以將暫時用不到的Bitmap對象及時回收掉;

(5)自定義堆內存分配大小,優化Dalvik虛擬機的堆內存分配;(這裡可以參照一些第三方的圖片緩存框架)

場景演示

為了說明出現OOM的場景和解決OOM的方法,我們選取了兩款不同的機型來做比較:

(1)該應用展示一個gallery,該gallery只加載圖片,gallery的adapter中傳入圖片的路徑而不是圖片對象本身,adapter動態加載圖片;

(2)演示所用的圖片預存儲到sdcard的cache目錄下,文件名分別為a.jpg,b.jpg…r.jpg,總共18張;

(3)圖片為規格1920*1200的jpg圖片,文件大小在423KB-1.48MB范圍內;

(4)運行環境:模擬器——android2.2版本系統——480*320屏幕尺寸;Moto Defy——2.3.4版本CM7系統——854*480屏幕尺寸;

1.演示一

首先采用最簡單的圖片加載方式,不帶任何圖片緩存、調整大小或者回收,SimpleImageLoader.class便是承擔此職責。加載圖片部分的代碼如下:

@Override

public Bitmap loadBitmapImage(String path) {

return BitmapFactory.decodeFile(path);

}

@Override

public Drawable loadDrawableImage(String path) {

return new BitmapDrawable(path);

}

演示結果:在模擬器上圖片只能加載1-3張,之後便會出現OOM錯誤;在Defy上不會出現錯誤;原因是兩者內存限制不同,Defy上運行的是第三方ROM,內存分配有40MB。另外gallery每次顯示一張圖片時,都要重新解析獲得一張圖片,盡管在Defy上還未曾出錯,但當圖片量加大,GC回收不及時時,還是有可能出現OOM。

2.演示二

為圖片加載的添加一個軟引用緩存,每次圖片從緩存中獲取圖片對象,若緩存中不存在,才會從Sdcard加載圖片,並將該對象加入緩存。同時軟引用的對象也有助於GC在內存不足的時候回收它們。常見的Discache就是這個原理,大家有興趣的可以自行研究。關鍵代碼

private HashMap> mImageCache;

@Override

public Bitmap loadBitmapImage(String path) {

if(mImageCache.containsKey(path)) {

SoftReferencesoftReference = mImageCache.get(path);

Bitmap bitmap = softReference.get();

if(null != bitmap)

return bitmap;

}

Bitmap bitmap = BitmapFactory.decodeFile(path);

mImageCache.put(path, new SoftReference(bitmap));

return bitmap;

}

@Override

public Drawable loadDrawableImage(String path) {

return new BitmapDrawable(loadBitmapImage(path));

}

3.演示三

為了進一步避免OOM,除了緩存,還可以對圖片進行壓縮,進一步節省內存,多數情況下調整圖片大小並不會影響應用的表現力。這個也是我之前必定做的,就是對圖片進行壓縮。

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;//如果該 值設為true那麼將不返回實際的bitmap,也不給其分配內存空間,這樣就避免內存溢出.

BitmapFactory.decodeFile(path, options);

可以對圖片按尺寸壓縮,也是不錯的方案:

options.inSampleSize = Util.computeSampleSize(options, 600, (int) (1 * 1024 * 1024));

options.inJustDecodeBounds = false;

options.inDither = false;

options.inPreferredConfig = Bitmap.Config.ARGB_8888;

Bitmap bitmap = BitmapFactory.decodeFile(path, options);

4.演示四

在有些情況下,嚴重縮小圖片還是會影響應用的顯示效果的,所以有必要在盡可能少地縮小圖片的前提下展示圖片,手動去回收圖片就變得尤為重要。所以這也是一些第三方圖片庫管理的時候必定用到lrucache算法的原因。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved