如何实时清除位图内存?

时间:2013-05-20 08:18:04

标签: java android performance

我创建了14个这样的Bitmap对象:

bmp[0]=BitmapFactory.decodeResource(getResources(), R.drawable.a0000);
bmp[1]=BitmapFactory.decodeResource(getResources(), R.drawable.a0001);
bmp[2]=BitmapFactory.decodeResource(getResources(), R.drawable.a0002);
bmp[3]=BitmapFactory.decodeResource(getResources(), R.drawable.a0003);
bmp[4]=BitmapFactory.decodeResource(getResources(), R.drawable.a0004);
bmp[5]=BitmapFactory.decodeResource(getResources(), R.drawable.a0005);
bmp[6]=BitmapFactory.decodeResource(getResources(), R.drawable.a0006);
bmp[7]=BitmapFactory.decodeResource(getResources(), R.drawable.a0007);
bmp[8]=BitmapFactory.decodeResource(getResources(), R.drawable.a0008);
bmp[9]=BitmapFactory.decodeResource(getResources(), R.drawable.a0009);
bmp[10]=BitmapFactory.decodeResource(getResources(), R.drawable.a0010);
bmp[11]=BitmapFactory.decodeResource(getResources(), R.drawable.a0011);
bmp[12]=BitmapFactory.decodeResource(getResources(), R.drawable.a0012);
bmp[13]=BitmapFactory.decodeResource(getResources(), R.drawable.a0013); 

这些位图用于制作背景动画,资源是14 xpj图像的320x480像素。所以我创建了一个自定义视图,然后在onDraw方法中调用位图。然后我在我的手机上测试了具有相同分辨率的应用程序,它运行顺畅,然后我尝试在具有更大分辨率的平板电脑上使用该应用程序(如1280x720),但我的背景不适合整个屏幕,所以我研究了如何通过基于设备分辨率制作具有不同分辨率的新位图来填充整个屏幕,结果如下:

newWidth= context.getResources().getDisplayMetrics().widthPixels;
newHeight= context.getResources().getDisplayMetrics().heightPixels;

int contador=0;

        do{
             bmp[contador]= Bitmap.createScaledBitmap(bmp[contador], newWidth,                   newHeight,true);
       contador++;
       }while(contador<13);

然后我简单地将这些行放在我的onDraw方法上。

   canvas.drawBitmap(bmp[i], 0, 0, null);
    i++;

如果我在手机上测试应用程序它运行正常,但是当我在平板电脑上测试它时,我会发现“位图大小超过VM预算”错误...所以我调查了一下,我有以下解决方案:创建原始的14 bmp Bitmap对象并制作第二个位图数组,名为bmp2,然后只在需要时分配位图,然后在我的onDraw方法中清除它:

   bmp2[i]= Bitmap.createScaledBitmap(bmp[i], newWidth, newHeight,true);
  canvas.drawBitmap(bmp2[i], 0, 0, null);
 bmp2[i].recycle();
 bmp2[i]=null;

它可以在我的平板电脑和手机上工作,但是我认为是非常糟糕的性能是因为我实时分配图像(在onDraw方法上)但是如果我使用循环方法并且不再分配bmp2那里将不是一个新的bmp2 ...

所以最后我真正的问题是:在我显示图像后如何清除一些内存,然后当我再次需要它时我可以使用它。谢谢!

4 个答案:

答案 0 :(得分:1)

我担心没有使用缩放位图进行全屏动画的安全方法。 为什么呢?

让我们做一些计算。你的每个初始位图都是320x480,是吗?这是320 * 480 * 4 * 14 = 8601600,大约是8Mb的内存。当您扩展到1280x720时,您加起来为1280 * 720 * 4 * 14 = 51609600字节,即49兆字节。 49 + 8 = 57兆字节。鉴于最新的平板电脑最多为您的应用VM分配了64兆字节,毫无疑问它不适合。即使它适合您的平板电脑,如果Nexus 10所有者会购买您的应用,会发生什么? N10的分辨率为2560×1600(更不用说缩放的位图看起来很可怜​​)。

为单帧分配单个位图几乎不会让你拥有流畅的动画,我担心。您可以尝试同时保留一个5位图的窗口并回收其他窗口,但我仍然不会这样做就足够了。除此之外,这会耗费大量CPU工作以进行恒定的位图缩放,并会破坏您的电池。

如果你真的想要一个动画背景,你应该看看OpenGL或TextureView

答案 1 :(得分:1)

其他人已经提到如何扩大小位图以填充大屏幕将无法提供高质量的结果。但无论如何,为了回答您的具体问题,您可以将这些低分辨率位图缩放到填充屏幕而不会出现内存错误。

您需要使用其中一种替代Canvas.drawBitmap()方法,这些方法可以在绘制时将位图缩放到正确的大小。

例如:

public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)

来自the Javadoc

  

绘制指定的位图,自动缩放/平移以填充   目标矩形。

dst矩形设置为您之前计算的屏幕尺寸。 然后,您不需要在内存中创建单独的缩放位图,因此您的问题就会消失。

答案 2 :(得分:0)

您应该为平板电脑和其他高级屏幕设计新的位图,并将它们放在res目录下的xhdpi文件夹中。这是最有效的选择。让Android操作系统为您提供最合适的资源。

有关详细帮助,请参阅此处 http://developer.android.com/training/multiscreen/index.html

这就是文档所说的

  

虽然系统执行缩放和调整大小以使您的   应用程序在不同的屏幕上工作,你应该努力   针对不同的屏幕尺寸和密度优化您的应用。在   这样做,您可以最大化所有设备和您的用户体验   用户认为您的应用程序实际上是为他们设计的   设备 - 而不是简单地拉伸以适应他们的屏幕   设备

答案 3 :(得分:0)

GC大部分时间都可以完成这项工作。

您应该按照文件夹(xhdpi,hdpi等)处理不同的位图分辨率。

您还应该检查BitmapFactory.Options,以便通过BitmapFactory签名生成质量较低的版本位图。

修改

您可能还需要考虑将WeakReferences用于您的位图。