论坛首页 移动开发技术论坛

Android 那些你所不知道的Bitmap对象详解

浏览 1186 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2014-11-18   最后修改:2014-11-18

  作者:近乎团队

我们知道Android系统分配给每个应用程序的内存是有限的,Bitmap作为消耗内存大户,我们对Bitmap的管理稍有不当就可能引发OutOfMemoryError,而Bitmap对象在不同的Android版本中存在一些差异,今天就给大家介绍下这些差异,并提供一些在使用Bitmap的需要注意的地方。

 

  在Android2.3.3(API 10)及之前的版本中,Bitmap对象与其像素数据是分开存储的,Bitmap对象存储在Dalvik heap中,而Bitmap对象的像素数据则存储在Native Memory(本地内存)中或者说Derict Memory(直接内存)中,这使得存储在Native Memory中的像素数据的释放是不可预知的,我们可以调用recycle()方法来对Native Memory中的像素数据进行释放,前提是你可以清楚的确定Bitmap已不再使用了,如果你调用了Bitmap对象recycle()之后再将Bitmap绘制出来,就会出现"Canvas: trying to use a recycled bitmap"错误,而在Android3.0(API 11)之后,Bitmap的像素数据和Bitmap对象一起存储在Dalvik heap中,所以我们不用手动调用recycle()来释放Bitmap对象,内存的释放都交给垃圾回收器来做,也许你会问,为什么我在显示Bitmap对象的时候还是会出现OutOfMemoryError呢?

 

  在说这个问题之前我顺便提一下,在Android2.2(API 8)之前,使用的是Serial垃圾收集器,从名字可以看出这是一个单线程的收集器,这里的”单线程"的意思并不仅仅是使用一个CPU或者一条收集线程去收集垃圾,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,Android2.3之后,这种收集器就被代替了,使用的是并发的垃圾收集器,这意味着我们的垃圾收集线程和我们的工作线程互不影响。

 

  简单的了解垃圾收集器之后,我们对上面的问题举一个简单的例子,假如系统启动了垃圾回收线程去收集垃圾,而此时我们一下子产生大量的Bitmap对象,此时是有可能会产生OutOfMemoryError,因为垃圾回收器首先要判断某个对象是否还存活(JAVA语言判断对象是否存活使用的是根搜索算法 GC Root Tracing),然后利用垃圾回收算法来对垃圾进行回收,不同的垃圾回收器具有不同的回收算法,这些都是需要时间的, 发生OutOfMemoryError的时候,我们要明确到底是因为内存泄露(Memory Leak)引发的还是内存溢出(Memory overflow)引发的,如果是内存泄露我们需要利用工具(比如MAT)查明内存泄露的代码并进行改正,如果不存在泄露,换句话来说就是内存中的对象确实还必须活着,那我们可以看看是否可以通过某种途径,减少对象对内存的消耗,比如我们在使用Bitmap的时候,应该根据View的大小利用BitmapFactory.Options计算合适的inSimpleSize来对Bitmap进行相对应的裁剪,以减少Bitmap对内存的使用,如果上面都做好了还是存在OutOfMemoryError(一般这种情况很少发生)的话,那我们只能调大Dalvik heap的大小了,在Android 3.1以及更高的版本中,我们可以在AndroidManifest.xml的application标签中增加一个值等于“true”的android:largeHeap属性来通知Dalvik虚拟机应用程序需要使用较大的Java Heap,但是我们也不鼓励这么做。

 

  在Android 2.3及以下管理Bitmap

 

  从上面我们知道,在Android2.3及以下我们推荐使用recycle()方法来释放内存,我们在使用ListView或者GridView的时候,该在什么时候去调用recycle()呢?这里我们用到引用计数,使用一个变量(dispalyRefCount)来记录Bitmap显示情况,如果Bitmap绘制在View上面displayRefCount加一, 否则就减一, 只有在displayResCount为0且Bitmap不为空且Bitmap没有调用过recycle()的时候,我们才需求对该Bitmap对象进行recycle(),所以我们需要用一个类来包装下  (Bitmap对象),代码如下

01.package com.example.bitmap;
02.import android.content.res.Resources;
03.import android.graphics.Bitmap;
04.import android.graphics.drawable.BitmapDrawable;
05.public class RecycleBitmapDrawable extends BitmapDrawable {
06.private int displayResCount = 0;
07.private boolean mHasBeenDisplayed;
08.public RecycleBitmapDrawable(Resources res, Bitmap bitmap) {
09.super(res, bitmap);
10.}
11. 
12. 
13./**
14.* @param isDisplay
15.*/
16.public void setIsDisplayed(boolean isDisplay){
17.synchronized (this) {
18.if(isDisplay){
19.mHasBeenDisplayed = true;
20.displayResCount ++;
21.}else{
22.displayResCount --;
23.}
24.}
25. 
26.checkState();
27. 
28.}
<div class="line alt1"
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics