【问题标题】:Android out-of-memory crash relating to configuration of drawable resource direcories与可绘制资源目录的配置相关的 Android 内存不足崩溃
【发布时间】:2013-06-01 07:14:58
【问题描述】:

原来一切都很好。我一直在使用 5 个可绘制目录

drawable-hdpi
drawable-ldpi
drawable-mdpi
drawable-xhdpi
drawable-xxhdpi

这是我最近创建一个新项目时由 eclipse adt-bundle 为我创建的。因此,当我需要一个新的位图时,我一直将位图的副本放入这 5 个目录中的每一个中。这对我来说总是有点奇怪,所以我很高兴通过阅读the Android documentation Providing Resources 发现我可以为所有常见位图创建一个“可绘制”目录。所以我换了

drawable
drawable-hdpi
drawable-ldpi
drawable-mdpi
drawable-xhdpi
drawable-xxhdpi

原来 5 个目录中剩下的唯一文件是最初创建项目时为我创建的“ic_launcher.png”文件。

但是,可绘制目录的新配置严重失败。加载 36k 位图文件 frame.png,现在由于该行而发生内存不足错误

 bitmap_fancyframe = BitmapFactory.decodeResource(getResources(), R.drawable.frame);

logcat 显示 Android 现在尝试分配 6790156 字节的内存块,结果该行(即 logcat 底部提到的 DrawOnTop.java:95 行)

06-01 07:26:53.995: I/dalvikvm-heap(1530): Forcing collection of SoftReferences for 6790156-byte allocation
06-01 07:26:54.025: D/dalvikvm(1530): GC_BEFORE_OOM freed 9K, 14% free 53820K/62343K, paused 27ms, total 27ms
06-01 07:26:54.025: E/dalvikvm-heap(1530): Out of memory on a 6790156-byte allocation.
06-01 07:26:54.025: I/dalvikvm(1530): "main" prio=5 tid=1 RUNNABLE
06-01 07:26:54.025: I/dalvikvm(1530):   | group="main" sCount=0 dsCount=0 obj=0x41077508 self=0x40de49a0
06-01 07:26:54.025: I/dalvikvm(1530):   | sysTid=1530 nice=0 sched=0/0 cgrp=apps handle=1075179312
06-01 07:26:54.025: I/dalvikvm(1530):   | schedstat=( 681383064 1229707806 4777 ) utm=53 stm=14 core=0
06-01 07:26:54.025: I/dalvikvm(1530):   at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
06-01 07:26:54.025: I/dalvikvm(1530):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:623)
06-01 07:26:54.025: I/dalvikvm(1530):   at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:476)
06-01 07:26:54.025: I/dalvikvm(1530):   at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:499)
06-01 07:26:54.025: I/dalvikvm(1530):   at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:529)
06-01 07:26:54.025: I/dalvikvm(1530):   at com.example.MyApp.DrawOnTop.<init>(DrawOnTop.java:95)

谁能解释为什么会这样?更重要的是,该 frame.png 文件在我的代码中被缩放和拉伸,所以我真的不需要它的 5 个副本,所以有什么办法可以在没有这些的一个“可绘制”目录中拥有所有常见的 png 位图有问题吗?

更新感谢@sam 的评论和@ken-wolf 的回答,我现在了解到,如果正确类型的位图不可用,Android 会进行大量位图缩放。所以当我简单地在所有目录之间复制相同的位图时,我的新理解是这样做的效果是位图会在没有缩放的情况下加载。对我来说,在扩展过程中显然出了点问题,但由于我正在自己进行扩展,所以我也不需要 Android 来做到这一点。所以我现在认为重要的问题是:我如何设置我的应用程序以便只提供每个位图的一个版本,并指示 Android 不要进行任何位图缩放

【问题讨论】:

标签: android android-resources android-drawable android-memory


【解决方案1】:

在这里直奔问题的核心:

如何设置我的应用程序,以便只提供每个位图的一个版本...

只需将您的位图放入您的drawable 目录之一即可。我相信它必须是一个比目标设备更小的 DPI。但随后,Android 将在内存中为具有更大 DPI 的设备创建一个缩放版本。我还相信,如果你只使用drawable 目录,Android 会假定它是中等 DPI,你得到的结果与将它放在 drawable-mdpi 中的结果相同。请注意,缩放后的图像实际上是不同的尺寸(以像素为单位),但 以英寸/DP 为单位的尺寸大致相同。在xxhdpixxxhdpi 屏幕上,内存版本最终可能会非常庞大​​。例如,我有一个来自 iPhone Retina 版本产品的 640x960 背景图像。 (这可能属于hdpi,我应该生成更小的版本)。如果你把它放在drawable-mdpi 中,Android 会在xxhdpi 设备上将它缩放 3 倍,所以它最终为 1920x2880,每像素 32 位,我认为大约是 22 兆。

并指示 Android 不要进行任何位图缩放。

要在加载时不进行位图缩放,请使用drawable-nodpi 目录。您必须在绘制时或在布局中手动缩放(使用 android:scaleType="fitXY" 或类似的,如果您有任何查询图像大小的代码,它将始终返回相同的 pixel 计数。质量是难以察觉的不同(如果这是您唯一的尺寸)。性能明显更好,并且内存中没有巨大的图像,只有原始尺寸的图像。

【讨论】:

    【解决方案2】:

    最好在每个相应文件夹中为每个图像提供不同大小的版本(实际宽度 x 高度像素大小)。这可确保 Android 根据设备选择合适的图像以提供最清晰的图像。您只能将它们全部放在/drawable/ 文件夹中,但这会导致图像看起来模糊 - 这在较高密度下尤其明显。再读一遍,它解释得很好:Supporting Multiple Screens

    “默认”资源是那些没有用配置限定符标记的资源。例如drawable/中的资源就是默认的drawable资源。系统假定默认资源是为基线屏幕尺寸和密度设计的,即正常屏幕尺寸和中等密度。因此,系统会酌情为高密度屏幕放大默认密度资源,为低密度屏幕缩小默认密度资源。

    关于位图内存不足错误,这是与 Android 上的内存分配有关的复杂问题。不幸的是,您无法提前准确地知道您有多少可用内存,并且将位图放入内存非常昂贵。在不了解应用程序的其余部分的情况下,很难给出准确的解决方案,但您可以采取一些防御措施来确保不会发生这种情况,包括:

    • 对位图进行全局静态引用并重新使用它
    • 确保从视图中删除对该位图的任何引用,并在完成后调用 Bitmap.recycle()
    • 使用Memory Cache

    【讨论】:

    • 感谢您的有用评论:-)。尽管您的任何想法都无法解决内存不足错误。导致内存不足的 png 文件在磁​​盘上只有 36kb,因此系统正在寻找分配 6790156 的事实对我来说似乎很荒谬,因为Supporting Multiple Screens 上的信息谈到按 1 阶因子(0.5, 0.75 等)。如果我只是将位图复制到所有不同的可绘制目录中,整个应用程序工作正常,不会消耗太多内存。
    • 我不是关于如何在 Android 上分配内存的内部工作的专家,但是在所有文件夹中复制相同的位图对我来说似乎是错误的。直觉上,我觉得让系统为您的设备使用最接近的“正确”尺寸,而不是放大或缩小,会更好。不知道你测试的是什么设备?可能是您的大位图正在缩小,这导致了问题。
    • 确实,从直觉上看,这对我来说也是错误的。我正在Samsung Galaxy S4 上进行测试,这是一款相当新的手机(并且仅针对 API 版本 14 及更高版本进行开发),所以我认为它会升级而不是降级。
    • Galaxy S4 似乎是 xxhdpi - 我会尝试看看您是否发现将图像 just 放入该文件夹(从所有其他文件夹中删除)或放入可绘制/文件夹。抱歉,如果您已经尝试过。根据我的经验,内存不足错误非常依赖于设备。
    • 感谢您的建议,但我不清楚沿着这条路走下去能否为我提供一个好的解决方案。所以我在问题的底部添加了一个“更新”部分。我认为现在真正的问题是,如何禁用 Android 在幕后执行的自动缩放功能?
    【解决方案3】:

    您将位图添加到 drawable-nodpi 文件夹。如果你不想要任何缩放。或者从清单中禁用自动缩放。

    http://developer.android.com/guide/practices/screens_support.html#DensityConsiderations

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多