Android Bitmap内存管理,解决内存溢出问题(1)之自定义BitmapDrawable

在Android 2.3.3或者更低版本下的时候,对于释放Bitmap的内存调用recycle()方法是必要的。否则在加载大量Bitmap的时候很容易就造成 OutOfMemoryError 。recycle()能够及时的释放Bitmap内存

注意:只有在不用Bitmap的时候才能调用recycle(),否则会造成Canvas: trying to use a recycled bitmap问题。


内存管理的全部实现有点复杂,但是把复杂的问题拆分开来作就非常简单了,在本章中只是实现能够自己释放内存的


BitmapDrawable。代码如下:

public static final String	TAG					= "RecyclingBitmapDrawable";

	/**
	 * 正在使用(显示)的计数
	 * */
	private int					mDisplayRefCounts	= 0;

	/**
	 * 正在被缓存的计数
	 * */
	private int					mCacheRefCounts		= 0;

	/**
	 * 是否已经被显示过了
	 * */
	private boolean				mHasDisplay			= false;

	public RecyclingBitmapDrawable(Resources res, Bitmap bitmap) {
		super(res, bitmap);
		// TODO Auto-generated constructor stub
	}

	/**
	 * 
	 * 设置BitmapDrawable是否正在显示,如果显示这里传入true,如果不再显示了这里传入 false
	 * 
	 * @param isDisplayed
	 *            是否显示
	 * */
	public void setIsDisplayed(boolean isDisplayed) {
		synchronized (this) { // 保持同步,防止多个线程修改数据时造成 Canvas: trying to use a
								// recycled bitmap或者 OutOfMemoryError
			if (isDisplayed) {
				mDisplayRefCounts++;
				mHasDisplay = true;
			} else {
				mDisplayRefCounts--;

			}
		}

		// 这个不需要同步
		checkState();
	}

	/**
	 * 设置BitmapDrawable是否正在被缓存,如果被缓存了这里传入true,否则传入 false
	 * */
	public void setIsCached(boolean isCached) {
		synchronized (this) {
			if (isCached) {
				mCacheRefCounts++;
			} else {
				mCacheRefCounts--;
			}
		}
		checkState();
	}

	// 检测显示和缓存状态,如果计数都为0的话,就释放Bitmap
	private void checkState() {
		synchronized (this) {
			if (mDisplayRefCounts <= 0 && mCacheRefCounts <= 0 && mHasDisplay && hasVildBitmap()) {
				if (BuildConfig.DEBUG) {
					System.out.println(TAG + "--" + "释放不再使用的Bitmap");
					getBitmap().recycle();
				}
			}
		}
	}

	// 检测Bitmap是否可用,Bitmap不能为空,并且没有被释放
	private boolean hasVildBitmap() {
		synchronized (this) {
			Bitmap bitmap = getBitmap();

			return bitmap != null && !bitmap.isRecycled();
		}
	}


在这里不得不说下在 Android2.3.3或更高版本上的Bitmap内存处理,为了更有效的利用Bitmap的内存,要充分利

用 BitmapFactory.Options.inBitmap 这个字段,具体内容查看http://blog.csdn.net/hello_tree/article/details/11732293


在这里总结下android不同版本对于图片存储和释放的不同之处:


①在过去通过 SoftReference或者WeakReference来缓存Bitmap,但是从Android 2.3(API Level 9)开始,就不推荐

使用了,因为从2.3开始垃圾回收器会非常积极的回收 soft/weak 引用,这使得这样缓存相当无效。


②在Android3.0(API Level 11)之前,bitmap的像素数据是存储在 in native memory 本地的,是和Bitmap自己分

开存储的,Bitmap存储在 Dalvik heap中,Bitmap的像素数据(在 native memeory中)的释放是不可预见的,这

可能导致程序内存不够从而崩溃。在Android 3.0(API Level 11)开始,Bitmap的像素数据和相关的Bitmap一块存储

在 Dalvik heap中。


③在Android 3.0(API Level 11)之前,如果加载大量bitmap数据在你的app 中时,应该在不用Bitmap的时候调用

recycle()方法,recycle()方法允许app尽快的回收内存(由于在 3.0之前Bitmap的后台像素数据和Bitmap是分开存

储的,并且后台数据的释放是不可预见的,所以通过手动调用Bitmap的recycle()方法来释放内存)。


④在Android 3.0(API Level 11)和之后的版本中,由于bitmap的后台像素数据和它本身一块存储在虚拟机堆(Dalvik

 heap)中,所

以不用手动调用Bitmap的recycle()方法,当没有引用指向Bitmap的时候,垃圾回收器会自动释放bitmap的内存。




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值