【问题标题】:dealing with many full screen png to avoid OOM处理许多全屏png以避免OOM
【发布时间】:2014-10-31 11:43:11
【问题描述】:

我有一个应用程序供我自己使用,用于与 arduino 通信。有自定义形状按钮,所以我在 PNG 中将它们绘制为单一背景,添加了 Buttonsandroid:background="@android:color/transparent" 以使它们在顶部透明,几乎与自定义按钮一样大。

在这张图片中,您可以看到: 1. 背景 - 黑色背景,深蓝色按钮绘制为单个 png。 2. 橙色 png - 与背景大小相同,使用match parrent 选项绘制。 3. 隐形按钮 - 有透明选项,蓝色方块,共有7个。

为了消除指示图像的错位,我在 PNG 透明背景中绘制了相同大小的背景。我将它们添加到 res/drawable 并在布局 XML 中作为 ImageViewandroid:visibility="gone",布局是 FrameLayout。为了表明该按钮被按下,我设置了橙色自定义按钮的VISIBLE,当arduino打开输出时,发回确认我让我离开并设置另一个可见的PNG。它消耗大量内存。图像尺寸为 1478x2623。在最坏的情况下,我只能永久显示 8 张图像 + 背景。在 onCreate 方法中,我加载了所有 17 张图片。

为了避免 OOM - 内存不足错误,我必须调整图像大小,这让我看起来很糟糕......

如果图像在 XML 中的可见性是android:visibility="gone",它会在 onCreate 中加载图像吗?如果是这样,我应该只在需要时创建、缩放和绘制。如何实现?

编辑

做了一些改变。

  1. 图片缩小到 1920x1080
  2. 8 ImageView 留在布局和资源中设置在方法中,而不是在 XML 中

这些更改使其速度更快,并且不再出现 OOM 错误。目前我很忙,所以需要一些时间来测试答案中建议的方法。我会尽快尝试的。

【问题讨论】:

  • @Funkystein 我明白,它的FrameLayout 所以我把每个都画在上面,它不会影响goneinvisible

标签: android image android-bitmap


【解决方案1】:

为什么你的图片这么大?这个分辨率(1478x2623)很大,在内存中保留8确实会导致OOM异常。

如果确实需要,您可以执行以下任一操作:

  1. 廉价而讨厌的解决方案:使用大内存堆。由于此应用程序供您个人使用,因此这可能是您最快的选择,并且可以在清单中进行一行更改,但我不建议将其用于一般应用程序,除非它需要更多内存的真正原因。 (要实现这一点,请参阅:How to increase heap size of an android application?
  2. 使用 UniversalImageLoadr (https://github.com/nostra13/Android-Universal-Image-Loader) 并确保不要一次加载所有图像。例如,仅当且仅当需要显示时才加载图像叠加层。您可以通过在需要时设置图像源并将不可见图像的图像源设置为 null 来做到这一点。此外,请确保回收您没有积极使用它们的位图。不过,其中大部分已由图像加载器库处理。
  3. (在我看来与 2 一起使用):您确实不需要您指定的分辨率。它太大了。您应该查看 Android 指南 (http://developer.android.com/training/displaying-bitmaps/index.html),或者使用图像加载器并指定更小的尺寸并加载缩放的图像。

要回答您的确切问题: 如果 XML 中图像的可见性是 android:visibility="gone",它会在 onCreate 中加载图像吗?如果是这样,我应该只在需要时创建、缩放和绘制。如何实现?

是的,它仍然会加载图像,因为它需要立即显示它,是的,您应该仅在需要时解码位图。关于如何实现这一点,请参见上面的第 2 点和第 3 点。

【讨论】:

  • 我使用android:largeHeap="true" 来避免OOM 错误。你能指导我解决问题吗?正如您在实心圆周围的图像区域中看到的那样,应该是直线。但是当调整大小时,它会变圆......我正在为 10.1" 4.4.2 平板电脑做这个应用程序
  • 如果您正在调整图像大小,您应该调整所有图像的大小,同时保持正确的纵横比。我还建议在您的 ImageView 中使用 scaleType 来查看它们中的任何一个是否为您提供所需的行为。请记住,您不必必须仅在 android 中调整大小,还可以使用 Photoshop 或其他图像编辑工具来帮助您。
  • 我不清楚。我使用 PAINT.NET 调整图像大小。我没有在 android 中调整图像大小,我只是将它们设为 visiblegone。目前我使用fitXY scaleType,它非常适合。我会检查 Universal loader 并给你反馈。
  • 嗯..你的回答给了我一些想法。我的布局中有 15 个ImageViews,设置为src。为什么我使用 XML 而不是 ImageView.setImageResource(...) 这样的代码。这很奇怪,为什么我没有考虑这个
  • 是的。在代码中执行此操作可为您提供更大的灵活性,特别是因为您只需要一个(或最多几个)在任何给定点处于活动状态。
【解决方案2】:

只是一个建议

为什么会发生 OOM? 应用程序正在尝试使用分辨率为 1478x2623 的图像。这是高分辨率图像。因此,当加载更多图像时,应用程序自然会更快耗尽内存。 如何避免这种情况? 试图在内存中保留较少数量的图像。可能可以使用定义大小的 LRU 缓存。但这不是他问题的解决方案,因为应用程序需要在同一屏幕上显示更多图像。 现在如何解决这个问题? 可以尝试利用 9-patch 图像概念。重复图案可以用较小的像素表示。这种方法的优点是不会因为拉伸而降低图像质量。

尝试一下或考虑一下。

【讨论】:

  • 很难理解你想说什么。请改写它,使其更具可读性:)
  • 谢谢ZAN的建议,能不能说的更准确点?我真的没明白你的意思
  • @Alfergon,我假设您知道称为 9-patch 的概念。为什么会发生OOM?应用程序正在尝试使用分辨率为 1478x2623 的图像。这是高分辨率图像。因此,当加载更多图像时,应用程序自然会更快耗尽内存。
  • 如何避免这种情况?试图在内存中保留较少数量的图像。可能可以使用定义大小的 LRU 缓存。但这不是他问题的解决方案,因为应用程序需要在同一屏幕上显示更多图像。现在如何解决这个问题?可以尝试利用 9-patch 图像概念。重复图案可以用较小的像素表示。这种方法的优点是不会因为拉伸而降低图像质量。 tekeye.biz/2012/android-9patch-files
  • @ZAN 不,我不知道所说的概念。如果它对问题有用,请将其包含在您的答案中(通过编辑它),以便提出问题的用户可以获得更多信息。
【解决方案3】:

你试过layer-list吗?我认为它是为这些情况而设计的,这意味着将drawable放在一起。那你该怎么办?首先减小图像大小,然后为每个按钮创建 layer-list

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item>
        <bitmap
            android:id="@+id/IdofNotPressed"
            android:gravity="fill"
            android:src="@drawable/notpressed" />
    </item>
    <item>
        <bitmap
            android:id="@+id/IdofPressed"
            android:gravity="fill"
            android:src="@drawable/pressed" />
    </item>   
</layer-list>

然后将这些可绘制对象设置为按钮的背景。然后得到他们的参考如下:

    final LayerDrawable background = (LayerDrawable) button.getBackground();

    background.getDrawable(0).setAlpha(255); // this is the lowest drawable visibale when no press occured 
    background.getDrawable(1).setAlpha(0);   // this is the top drawable which is shown as press state (orange)it is not visible by default

现在当你想要显示新闻状态时,你所要做的就是

    background.getDrawable(0).setAlpha(0);     // this is the lowest drawable
    background.getDrawable(1).setAlpha(255);   // this is the top drawable which is shown as press state (orange) now it is visible 

【讨论】:

  • 嗨,mmlooloo。我将图像缩小到 1920x1080。我不能将图像设置为按钮的背景,因为它们会叠加,所以我只是让它们不可见并且它们不会叠加。在点击的那一刻,我显示图像,以便用户获得反馈。 @kha 给了我一些想法,我正在努力。但是一天只有24小时:)
  • 嗨 :-)。“我不能将图像设置为按钮的背景,因为它们会重叠”我只是希望您将图像放入图层列表并像只有一个背景一样处理它。如果你有时间试试。
  • 说清楚。每个“按钮”有 3 种状态 1. 开始(或未按下时不显示图像) 2. 进行中(按下时为橙色图像) 3. 完成(收到反馈时问题图像中未显示蓝色图像)。当从服务器获得反馈时,状态会发生变化。它有点不是按钮的状态
  • 为了更清楚,您可以使用我的解决方案处理任意数量的状态。这只是我使用 2 个位图的示例。无论如何做你喜欢的事。
  • 我会尝试你的建议 :) 我只是想尽可能地清楚 :) 我觉得我让你失望了不管你喜欢做什么。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-13
  • 1970-01-01
  • 2011-04-14
相关资源
最近更新 更多