【问题标题】:Android setBackgroundResource cause out of memory excepitonAndroid setBackgroundResource 导致内存不足异常
【发布时间】:2012-12-15 06:51:59
【问题描述】:

我正在开发一个在 ViewPager 中显示 12 个视图的游戏本应用程序。 这是我的自定义 PagerAdapter :

private class ImagePagerAdapter extends PagerAdapter {

    private int[] mImages = new int[] { R.drawable.copertinai,
            R.drawable.blui, R.drawable.azzurroi, R.drawable.rossoi,
            R.drawable.gialloi, R.drawable.verdei, R.drawable.rosai,
            R.drawable.grigioi, R.drawable.neroi, R.drawable.arancionei,
            R.drawable.marronei, R.drawable.violai, R.drawable.ulm };

    @Override
    public int getCount() {
        return mImages.length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((RelativeLayout) object);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Context context = MainActivity.this;
        RelativeLayout relLayImageView = new RelativeLayout(context);
        relLayImageView.setBackgroundResource(mImages[position]);

        ((ViewPager) container).addView(relLayImageView, new LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        return relLayImageView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        ((ViewPager) container).removeView((RelativeLayout) object);
        object=null; 
        System.gc();
    }
}

在某些设备中,当调用这行代码时,它会随机导致内存不足异常

relLayImageView.setBackgroundResource(mImages[position]);

但在所有设备中,当我翻页时,我都会在 logcat 中看到类似的内容:

12-31 00:25:31.655: I/dalvikvm-heap(9767): Grow heap (frag case) to 50.875MB for 10384016-byte allocation

当我在另一个 Activity 中根据用户操作为主布局设置不同的背景资源时,该应用也会因同样的问题在某些设备中崩溃。代码如下:

            btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {


                colorButtons.get(indiceColoreAttuale).setBackgroundResource(
                                unSelectedColorsRes[indiceColoreAttuale]);

                switch (index) {
                case 0:
                    mainLayout.setBackgroundResource(R.drawable.blus);
                    break;
                case 1:
                    mainLayout
                            .setBackgroundResource(R.drawable.azzurros); 
                    break;
                case 2:
                    mainLayout
                            .setBackgroundResource(R.drawable.rossos);
                    break;
                case 3:
                    mainLayout
                            .setBackgroundResource(R.drawable.giallos);
                    break;
                case 4:
                    mainLayout
                            .setBackgroundResource(R.drawable.verdes);
                    break;
                case 5:
                    mainLayout
                            .setBackgroundResource(R.drawable.rosas);
                    break;
                case 6:                     
                    mainLayout
                            .setBackgroundResource(R.drawable.grigios);
                    break;
                case 7:
                    mainLayout
                            .setBackgroundResource(R.drawable.neros);
                    break;
                case 8:
                    mainLayout
                            .setBackgroundResource(R.drawable.arancios);
                    break;
                case 9:
                    mainLayout
                            .setBackgroundResource(R.drawable.marrones);
                    break;
                case 10:
                    mainLayout
                            .setBackgroundResource(R.drawable.violas);
                    break;
                }

                mainLayout.startAnimation(animationShowTextColor);
                mainLayout.setGravity(Gravity.CENTER_HORIZONTAL);
                indiceColoreAttuale = index;
                colorButtons.get(index).setBackgroundResource(
                        selectedColorsRes[index]);

            }
        });

当我在 mainLayout 上调用 setBackgroundResource() 时,它再次运行异常。

希望您能帮我解决这个问题,在此先感谢!

【问题讨论】:

  • 听起来您正在加载一些 巨大 背景,而设备没有足够的内存供它们使用...
  • 是的,但有时会发生在具有大量内存的设备上,而不会发生在内存较少的设备上。我加载的图像不是很大(从 50 到 200 kb)。跨度>
  • 它们听起来并不巨大。在更改背景资源之前,您可以自己尝试recycle-ing 位图。获取旧的背景drawable并在更改后查看它是否为BitmapDrawable,如果是则在其Bitmap上调用recycle()
  • 谢谢,我试过了,但不幸的是,在第四次更改背景资源后,我得到了“IllegaArgumentException:无法绘制回收位图”
  • 图像文件大小通常与所需的内存量无关(通常对于 jpg 更是如此,但与 png 类似)。所需内存基于每个像素的宽度、高度和字节数(所需内存 = 宽度 x 高度 x 字节/像素)。您正在加载的图片的尺寸是多少?

标签: android exception memory android-viewpager android-drawable


【解决方案1】:

我解决了!你所有的提示都很好,但真正的问题是“/drawable”文件夹!我将所有图片都放在系统认为的“/drawable”通用文件夹中,例如“/drawable/mdpi”,所以当我在具有hdpi或更多的设备中运行时,图像被调整大小,并且变得太大导致OutOfMemoryException!

现在我使用“/drawable-nodpi”来存储我的图像。此文件夹的作用类似于“/drawable”,但图像永远不会调整大小!

【讨论】:

  • 我想你的意思是'drawable-nodpi'
  • 我注意到内存使用量显着下降。这个解决方案有什么缺点吗?
  • 这是一个很好的答案,我花了一段时间才找到它,我无法在任何地方的 androids 文档中看到它。
【解决方案2】:

每个 Android 应用程序都有有限的内存(堆)可供 Dalvik VM 使用。在某些设备上是 32 MB,它是 64 MB。当您设置后台资源时,您将该资源加载到堆上。该资源作为位图加载 - 它的大小是宽度 * 高度 * 像素大小。通常位图作为 ARGB 图像加载,每个像素有 4 个字节。这意味着加载 1024x768 图像在堆上占用 1024*768*4 = 3145728 B = 3072 kB = 3 MB。当您加载大量大图像时,它会消耗所有可用的堆内存并导致内存不足异常。

要解决此问题,最好加载尽可能小的图像 - 当您显示图像的缩略图时,以不大于显示的具体部分的分辨率的分辨率加载它就足够了。这意味着当您在 800x600 显示器上显示图像时,加载 1024x768 图像是不够的。您可以使用 BitmapFactory 加载更小分辨率的图像。

使用方法decodeResource(activity.getResources(), R.drawable.imageId, opts)。 BitmapFactory.Options opts 具有参数inSampleSize ,您可以在其中设置图像的二次采样。也可以使用参数inPreferredConfig 来设置RGB_565 而不是ARGB_8888,以防您不需要透明度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 2013-06-22
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    相关资源
    最近更新 更多