与可绘制资源目录的配置相关的Android内存不足崩溃

时间:2013-06-01 07:14:59

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

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

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

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

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

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

但是,drawable目录的新配置失败了。加载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个副本,所以有没有办法可以在一个'drawable'目录中拥有所有常见的png位图而没有这些问题?

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

3 个答案:

答案 0 :(得分:3)

直接回答问题的核心:

  

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

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

  

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

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

答案 1 :(得分:1)

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

  

“默认”资源是未使用配置限定符标记的资源。例如,drawable /中的资源是默认的可绘制资源。系统假定默认资源是针对基线屏幕尺寸和密度设计的,这是正常的屏幕尺寸和中等密度。因此,系统会根据需要为高密度屏幕缩放默认密度资源,为低密度屏幕缩小默认密度资源。

对于位图内存不足错误,这是一个与Android上的内存分配相关的复杂问题。遗憾的是,您无法准确地预先知道您有多少可用内存,并且将Bitmaps放入内存非常昂贵。如果不了解您的其他应用程序,很难给出确切的解决方案,但您可以采取防御性措施来确保不会发生这种情况,包括:

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

答案 2 :(得分:1)

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

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