带位图的内存不足异常

时间:2013-02-13 22:05:12

标签: android bitmap surfaceview out-of-memory bitmapfactory

我的应用中存在问题。切换到LANDpace模式时,会调用setContentView()方法来显示钢琴键盘。钢琴键盘类扩展了Surfaceview,可以更好地显示按键。此SurfaceView类作为子项添加到我的横向布局:

RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.rootLayout);
RelativeLayout.LayoutParams relativeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
relativeLayoutParams.addRule(RelativeLayout.BELOW, R.id.relativeLayoutLowerBar);
rootLayout.addView(keyboardSurfaceView, relativeLayoutParams); 

在我的keyboardSurfaceView类中,使用BitmapFactory.decodeResource()方法在Bitmap数组中加载位图并保持位图直到应用程序被销毁。这非常有效。当我在纵向模式下切换时,我用setContentView()更改布局并删除keyboardSurfaceView:

if(keyboardSurfaceView != null && keyboardSurfaceView.getParent() != null)
        ((ViewGroup) keyboardSurfaceView.getParent()).removeView(keyboardSurfaceView);

位图加载一次。第一次切换到横向模式。我遇到了一个内存不足的错误,当swichtin从风景中的protrait高达10-20次,等等。当我在ddms视图中更新堆时,我可以看到,每当我在横向视图中从protrait视图切换时,堆大小就会增长到大约。 20mb,然后应用程序崩溃。我不知道为什么这种情况一直在发生。位图只加载一次,而不是每次都加载。 我也试过bitmap.recycle(); bitmap = null但没有成功。还尝试使用Google最佳实践中描述的LRUCache类缓存位图。我还搜索了stackoverflow以找到解决问题的正确方法。仍然无法解决这个问题。我自己处理肖像/风景变化(使用onConfigurationChanged()方法覆盖)。将所有图像放在drawable-xhdpi中有点帮助。当改变方向时,堆大小和以前一样增长,但仍在增长。任何帮助将不胜感激......

例外:

 02-13 22:44:09.419: E/dalvikvm-heap(935): 11448-byte external allocation too large for this process.
02-13 22:44:09.419: E/dalvikvm(935): Out of memory: Heap Size=16391KB, Allocated=13895KB, Bitmap Size=16394KB, Limit=32768KB
02-13 22:44:09.419: E/dalvikvm(935): Trim info: Footprint=16391KB, Allowed Footprint=16391KB, Trimmed=432KB
02-13 22:44:09.419: E/GraphicsJNI(935): VM won't let us allocate 11448 bytes

2 个答案:

答案 0 :(得分:1)

这是有关如何有效处理位图的Android文档

  

http://developer.android.com/training/displaying-bitmaps/index.html

答案 1 :(得分:0)

好的第一次在我的surfaceView类中调用surfaceCreated时,我调用了这个方法,这个方法只被调用一次而不是每次我在屏幕上显示surfaceView时都会这样:

bitmapKeyboard = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyboard); 

bitmapGlowImages[0] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keycdown); 
bitmapGlowImages[1] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[2] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyddown);
bitmapGlowImages[3] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[4] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyedown);
bitmapGlowImages[5] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keycdown); 
bitmapGlowImages[6] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[7] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyddown);
bitmapGlowImages[8] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[9] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyddown);
bitmapGlowImages[10] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[11] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyedown);

在这个类中也运行一个单独的线程来绘制按下的键:canvas.drawBitmap(bitmap, null, destRect, null)。最后,当调用onDestroy时,我的方法recycleBitmaps()被称为

public void recycleBitmaps() {
        if(bitmapKeyboard != null) {
            bitmapKeyboard.recycle();
            bitmapKeyboard = null;
            for(int i = 0; i < bitmapGlowImages.length; i++) {
                bitmapGlowImages[i].recycle();
                bitmapGlowImages[i] = null;
            }
            System.gc();
        }
}

就是这样。每次在风景中,我都会将我的surfaceView添加到我的横向视图中的父视图中,并在纵向中将其再次删除,并加载我的纵向布局。我在onConfigurationChanged()中进行此操作,因为我自己处理方向更改,因此每次更改设备方向时都不会销毁和创建应用。