轉:http://blog.csdn.net/xuhui_7810/article/details/9493681
我們在代碼里調用setBackgroundResource(int resid)來設置一個view控件的背景時,如果圖片過大,或者調用setBackgroundResource(int resid)多次時,有可能導致內存溢出.查看代碼:
public void setBackgroundResource(int resid) {
if (resid != 0 && resid == mBackgroundResource) {
return;
}
Drawable d= null;
if (resid != 0) {
d = mResources.getDrawable(resid);
}
setBackgroundDrawable(d);
mBackgroundResource = resid;
}
可以發現,背景圖片最后設置為了一個Drawable對象.Drawable對象占用的內存分為java層的和底層的兩部份.JAVA層的內存,如果在你的view釋放時,你的背景圖片調用了Drawable的setCallback(null), 即取消你的背景圖片在VM里的引用,則JAVA這部份的內存空間,在系統調用GC函數時可以把它回收. 但是在native層的內存,GC是釋放不了的.這樣就會導致有內存泄漏. 解決這個問題的辦法有很多種,下面我來說說最簡單的一種:
設置背景時,不要調用setBackgroundResource(int resid),而改用setBackgroundDrawable(Drawable d) 這個函數,這個函數的參數d 用一個BitmapDrawable new出來.上代碼:
- Bitmap mBgBitmap = null;
- mBgBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.unlock_bg);
- setBackgroundDrawable(new BitmapDrawable(mBgBitmap));
這樣的好處就是,我們可以保留圖片的Bitmap引用mBgBitmap,在我們的VIEW釋放時,我們顯示的調用
- if(mBgBitmap != null && !mBgBitmap.isRecycled())
- {
- mBgBitmap.recycle();
- mBgBitmap = null;
- }
這段代碼,就可以把native層的內層也給釋放掉,這樣就可以徹底解決內存泄漏的問題
加上LruCache效果相比更佳
private LruCache mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
mMemoryCache = new LruCache(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
};
...
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
