为什么我的应用程序在屏幕旋转时泄漏内存?

时间:2016-04-27 13:31:38

标签: android memory-leaks bitmap rotation

我已经搜索了几小时关于内存泄漏的问题,我似乎无法解决我的问题。经过9次旋转后,我的应用程序崩溃并出现OutOfMemory错误。我的应用程序中有Bitmaps的Bitmaps和Drawables。我已经尝试将代码移除到drawables的回调,我已经尝试将所有Bitmaps设置为null以及手动调用垃圾收集器。我在onSaveInstanceState()方法中拥有所有这些代码,因为我认为只要屏幕发生变化并且在销毁视图之前就会调用它。这些解决方案都不起作用。

我得到了一些结果,Bitmaps变为null,但是在另一个内存泄漏之前只增加了另外9个屏幕旋转。我的泄漏在哪里?我究竟做错了什么?我的印象是,当一个屏幕旋转时,一切都被破坏并重新创建,这显然是错误的。

我不想发布我的代码,因为A.有很多它和B.它接近完成,所以成为公司秘密本身。如果有什么东西你必须绝对看到解决这个问题,那么我会发布它。我想我只需要一个非常好的解释,当屏幕旋转时实际发生了什么,以及如何正确处理位图和drawables。注意:如果我离开应用程序然后返回,则不会弹出此错误,只有在屏幕旋转时调整视图大小时才会出现此错误。

我有大约7个位图和7个drawable,都是在启动时创建的,并在屏幕旋转时调整大小。多次这样做会阻止应用程序。

一些简化的代码: 我如何设置一个可绘制的位图。这个也设置为ClipDrawable:

//Full Bar
        colorbarMap = BitmapFactory.decodeResource(res, R.drawable.colorbar);
        colorbarDraw = new BitmapDrawable(res, colorbarMap);
        colorbarDraw.setBounds(barX, barY, barX2, barY2);
        colorbarClip = new ClipDrawable(colorbarDraw, Gravity.BOTTOM, ClipDrawable.VERTICAL);
        colorbarClip.setBounds(barX, barY, barX2, barY2);
        colorbarClip.setLevel(currentLevel);

        //Empty Bar
        colorbaremptyMap = BitmapFactory.decodeResource(res, R.drawable.colorempty);
        colorbaremptyDraw = new BitmapDrawable(res, colorbaremptyMap);
        colorbaremptyDraw.setBounds(barX, barY, barX2, barY2);

上面的代码在视图初始化时基于以下代码运行一次:

private void init(){
        //System
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        res = getResources();
        options = new BitmapFactory.Options();

        viewTreeObserver = getViewTreeObserver();
        if (viewTreeObserver.isAlive()) {
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    view_width = getWidth();
                    view_height = getHeight();
                    afterLayout();
                }
            });
        }
}

第一个代码段在以下方法下运行:afterLayout()

此后没有用位图完成任务。基于视图宽度和高度,使用x和y位置初始化每个位图。使用矩形编辑该位置以设置其边界,例如移动对象。

1 个答案:

答案 0 :(得分:0)

如果要显示的位图小于使用此位图,或者您不需要高分辨率图像

  bitmapOption = new BitmapFactory.Options();
        bitmapOption.inScaled = true;
        bitmapOption.inSampleSize = 2;
  imageBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bitmapOption);

这会减少位图的大小,看看秃头家伙的解释

optimizing bitmap

将你的位图加载代码放入try finally块并在最后使用它

try {
      ...
 }finally {
      if (imageBitmap != null) {
                //recycle the bitmap to improve performance and avoid OO Exception
                imageBitmap.recycle();
                imageBitmap = null;
       }
  }

每当调用GC时,这将回收图像占用的位图空间