处理许多全屏png以避免OOM

时间:2014-10-31 11:43:11

标签: android image android-bitmap

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

enter image description here

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

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

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

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

修改

做了一些改变。

  1. 图片缩小为1920x1080
  2. 8在布局上留下了ImageView,资源是在方法中设置的,而不是在XML
  3. 这些更改使其更快,不再出现OOM错误。目前我很忙,所以需要一些时间来测试答案中建议的方法。我会尽快尝试。

3 个答案:

答案 0 :(得分:4)

为什么你的图片如此之大?这个分辨率(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),或者使用图片加载器并指定更小的尺寸并加载缩放图像。
  4. 回答您的确切问题: 如果XML中的图像可见性是android:visibility =“gone”,它是否会在onCreate中加载图像?如果是这样,我应该创建,缩放它,并在需要时绘制。如何实现?

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

答案 1 :(得分:2)

只是一个建议

为什么会发生OOM?         应用程序尝试使用分辨率为1478x2623的图像。哪个是高分辨率图像。因此,当加载更多图像时,应用程序会更快地进入内存状态。     怎么避免这个?          试图在内存中保留较少数量的图像。可以使用定义大小的LRU缓存。但这不是他的问题的解决方案,因为应用程序需要在同一屏幕中显示更多图像。     现在该如何解决?         可以尝试利用9补丁图像概念。其中重复图案可以用较小的像素表示。这种方法的优点是,由于拉伸,图像质量不会下降。

试一试或考虑一下。

答案 2 :(得分:2)

你试过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>

之后将那些drawables设置为按钮的背景。然后得到如下的参考文献:

    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