高效地加载图片(四) 管理缓存

分享到:

 

除了缓存图片意外,还有一些其他的方式来促进GC的效率和图片的复用.不同的Android系统版本有不同的处理策略.BitmapFun中就包含了这个类,能够使我们高效地构建我们的项目.

为了开始以下教程,我们需要先介绍一下Android系统对Bitmap管理的进化史.

  • 在Android2.2(API level 8)以及更低的版本中,当垃圾被回收时,应用的线程会被停止,这会造成一定程度的延时.在Android 2.3中,加入了并发回收机制,这意味着当Bitmap不再被使用的时候,内存会被很快地回收.
  • 在Android 2.3.3(API level 10)以及更低版本中,像素数据是被存储在本地内存中的,并且和Bitmap本身是分离的,Bitmap存储在Dalvik堆中.本地内存中的像素数据并不以一种可预知的方式释放,可能会造成应用内存溢出和崩溃.而在Android 3.0(API level 11)中,像素数据和Bitmap一起被保存在Dalvik堆中.

以下内容描述了如何为不同的Android版本选择最佳的图片缓存管理方式.

在Android 2.3.3以及更低版本中管理缓存

在Android 2.3.3(API level 10)以及更低版本中,建议使用Bitmap.recycle()方法.如果你正在展示大量的图片,应用可能会内存溢出.这时候recycle()方法可以使内存被尽可能快地回收.

注意:你只能在确定了Bitmap确实不再被使用了之后才能调用recycle()方法.如果你调用recycle()方法释放了Bitmap,而稍后却又使用这个Bitmap,这时就会出现"Canvas: trying to use a recycled bitmap"错误.

以下代码片段是recycle()方法调用的示例.这里使用了引用计数器的方式(通过变量mDisplayRefCount和mCacheRefCount)来追踪一个Bitmap是否还在被使用或者存在于缓存中.当满足如下条件时,此处就会回收Bitmap:

  • 引用计数器变量mDisplayRefCount和mCacheRefCount的值都为0时.
  • Bitmap不为null,而且没有被回收.
private int mCacheRefCount = 0;
private int mDisplayRefCount = 0;
...
// 通知当前Drawable,当前被使用的状态改变了
// 保持一个计数器,用来决定当前Drawable何时被回收
public void setIsDisplayed(boolean isDisplayed) {
    synchronized (this) {
        if (isDisplayed) {
			// 当被显示时,则计数器mDisplayRefCount的值+1
            mDisplayRefCount++;
			// 标志当前Drawable被显示了
            mHasBeenDisplayed = true;
        } else {
			// 当一个引用被释放时,计数器mDisplayRefCount的值-1
            mDisplayRefCount--;
        }
    }
    // 确认recycle()方法是否已经被调用了
    checkState();
}

// 通知当前Drawable缓存状态改变了
// 保持一个计数器用于决定何时这个Drawable不再被缓存
public void setIsCached(boolean isCached) {
    synchronized (this) {
        if (isCached) {
            mCacheRefCount++;
        } else {
            mCacheRefCount--;
        }
    }
    // 确认recycle()方法是否已经被调用了
    checkState();
}

private synchronized void checkState() {
	// 如果当前Drawable的内存和展示计数器都为0,而且当前Drawable还可用
	// 则释放掉它
    if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
            && hasValidBitmap()) {
        getBitmap().recycle();
    }
}

// 判断Drawable对应的Bitmap是否可用
private synchronized boolean hasValidBitmap() {
    Bitmap bitmap = getBitmap();
    return bitmap != null && !bitmap.isRecycled();
}
昵    称:
验证码:

相关文档: