您的位置:首页 > 移动开发 > Android开发

Android 管理Bitmap内存 及 Bitmap.Config BitmapFactory.Options 说明

2015-06-09 17:36 477 查看
BitmapFactory.Options options = new BitmapFactory.Options();

/*

ARGB: alpha, red, green, blue

ALPHA_8 8位 1byte每像素1字节  按官方注释是说,只存alpha值,测试后发现,图片照样显示。。

ARGB_4444   16位 2bytes  已过时 像素2字节  (argb各范围为4位,即0~16)

ARGB_8888   32位 4bytes  每像素4字节(argb各范围0~255) 默认值

RGB_565 16位 不含Alpha   每像素2字节r:5bits(0~32), g:6bits(0~64), b:5bits(0~32)  

测试发现内存的分配情况: ALPHA_8(23mb) ARGB_8888(23mb)  RGB_565(13mb) ARGB_4444(15mb)

以上是反复销毁再创建的内存分配情况,  看出 前两者 较大, 后两者 较小

*/

options.inPreferredConfig = Config.RGB_565; //图片颜色配置

options.inSampleSize = 2;  //宽高缩放比 这表示为原始的1/2

/*

如果设置为真,解码器将返回null(位图),但out..属性仍将被设置.

这时生成的bitmap为null, 调用options.outHeight
options.outWidth 能取到真实图片的宽高

*/

options.inJustDecodeBounds = true;  //仅仅解码 bounds 即宽高,存在对应的out属性中

通过目标size,计算缩放比例:

public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

final int halfHeight = height / 2;
final int halfWidth = width / 2;

// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}

return inSampleSize;
}


String imageType = options.outMimeType;  //图片的后缀名 比如jpeg png 这种

//decodeStream 比decodeResource 高效

Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

管理Bitmap内存

官方地址:http://developer.android.com/training/displaying-bitmaps/manage-memory.html

> 在Android的Android 2.2(API 8级)及以下,当垃圾收集发生时,您的应用程序的线程都停止了。这会导致延迟,会降低性能。

   在Android 2.3增加了并发垃圾回收,这意味着内存很快被回收后的位图不再引用。

> 在2.3及以下,the backing pixel data for a bitmap is stored in native memory.

  存储在native内存中的bitmap,不会被释放,可能导致超出内存极限,而报oom。

 在3.0及以上,bitmap的像素数据存储在Dalvik heap中的。

在2.3及以下管理Bitmap内存

 在2.3及以下,需要手动调用bitmap.recycle(),释放位图内存

  当调用该recycle()回收时,要确定该bitmap不再被使用。如果调用了recycle()后,又绘制该bitmap,将报异常:

       “Canvas: trying to use a recycled bitmap”

  下面的官方示例代码上,使用手动添加引用计数来处理,当mCacheRefCount、mDisplayRefCount都等0时才能recycle()

private int mCacheRefCount = 0;
private int mDisplayRefCount = 0;
...
// Notify the drawable that the displayed state has changed.
// Keep a count to determine when the drawable is no longer displayed.
public void setIsDisplayed(boolean isDisplayed) {
synchronized (this) {
if (isDisplayed) {
mDisplayRefCount++;
mHasBeenDisplayed = true;
} else {
mDisplayRefCount--;
}
}
// Check to see if recycle() can be called.
checkState();
}

// Notify the drawable that the cache state has changed.
// Keep a count to determine when the drawable is no longer being cached.
public void setIsCached(boolean isCached) {
synchronized (this) {
if (isCached) {
mCacheRefCount++;
} else {
mCacheRefCount--;
}
}
// Check to see if recycle() can be called.
checkState();
}
private synchronized void checkState() {
// If the drawable cache and display ref counts = 0, and this drawable
// has been displayed, then recycle.
if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
&& hasValidBitmap()) {
getBitmap().recycle();
}
}

//验证bitmap是否能被回收
private synchronized boolean hasValidBitmap() {
Bitmap bitmap = getBitmap();
return bitmap != null && !bitmap.isRecycled();
}


在3.0及以上管理内存

在3.0及以上添加了BitmapFactory.Options.inBitmap 标识,表示decode方法在加载内容将尝试加载它所指向的bitmap。

这意味着,位图被再利用,存储器不需要重新分配、解除分配,从而提高了性能。它存在的一定的限制,

在4.4以下时,只支持相同尺寸的bitmap;在4.4及以后,才支持不同尺寸的bitmap。

保存位图便于以后使用

Set<SoftReference<Bitmap>> mReusableBitmaps;
private LruCache<String, BitmapDrawable> mMemoryCache;

// If you're running on Honeycomb or newer, create a
// synchronized HashSet of references to reusable bitmaps.
if (Utils.hasHoneycomb()) {//3.0及以上
mReusableBitmaps =
Collections.synchronizedSet(new HashSet<SoftReference<Bitmap>>());
}

mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) {

// Notify the removed entry that is no longer being cached.
@Override
protected void entryRemoved(boolean evicted, String key,
BitmapDrawable oldValue, BitmapDrawable newValue) {
if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
// The removed entry is a recycling drawable, so notify it
// that it has been removed from the memory cache.
((RecyclingBitmapDrawable) oldValue).setIsCached(false);
} else {
// The removed entry is a standard BitmapDrawable.
if (Utils.hasHoneycomb()) {
// We're running on Honeycomb or later, so add the bitmap
// to a SoftReference set for possible use with inBitmap later.
mReusableBitmaps.add
(new SoftReference<Bitmap>(oldValue.getBitmap()));
}
}
}
....
}

使用保存的Bitmap

….代码省略
官方示例DisplayingBitmaps.zip 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: