【问题标题】:removing image data from memory从内存中删除图像数据
【发布时间】:2012-05-01 05:03:03
【问题描述】:

我必须相信有一种方法可以在不再需要图像数据时从内存中清除它,但尽管进行了详尽的搜索,我还是找不到解决方案。 stack 和 google android dev list 都充满了关于 OOM 错误的问题,特别是“位图大小超出 VM 预算”,但我仍然没有看到明确的答案。

我了解设备存在硬内存限制,并且我了解加载和显示或缓存大量图像数据是不现实的,但应该避免丢弃不再需要的数据。

例如,想象一下这个非常基本的假设应用程序,它模拟了本地图库应用程序的许多行为:

  1. 一个允许用户细读来自远程服务器的图像的图库。
  2. 该服务器上可能有任意数量的图像。
  3. 该应用一次显示 1 张图像,并允许用户通过按下按钮或滑动来一次后退或前进 1 张图像。
  4. 任何时候最多可以渲染 3 张图像(因此用户可以在滑动时立即看到当前图像左侧或右侧的图像)。应丢弃所有其他图像数据。
  5. 使用 URL.openStream 和 Drawable.createFromStream 或 BitmapFactory.decodeStream 加载图像。流已适当关闭。
  6. 在获取图像之前,在服务器上调整了合适的大小。
  7. 加载发生在 AsyncTasks 中。不再需要的任务(由于从具有不完整任务的图像中移开)被取消。 AyncTask 中的任何引用都是 WeaklyReferenced。
  8. 当不再需要任何图像时,它会通过以下方式“清除”:
    • getBackground().setCallback(null)
    • 监听器设置为空
    • setImageDrawable/Bitmap(null)
    • 删除视图

这个简单的结构考虑了我所知道的所有建议做法,在某些时候不可避免地会因 OOM 错误而崩溃。使用 BitmapFactory.Options inSampleSize 和 inPreferredConfig 将延迟不可避免的情况,但不会永远延迟,并且会以图像质量为代价。在此示例中,我使用了远程图像,但存储在 /assets/ 或内存等中的图像存在问题。

我的感觉是,如果我们可以在某一点显示 X 数量的图像数据,并且我们采取所有步骤从内存中删除该图像数据,那么以后应该能够显示相同数量的数据,而无需进行补偿对于之前发生的事情。

由于关于这个问题的问题数量众多,我希望有一个标准解决方案记录在案,但如果有的话,我找不到它。我看过 Romain Guy 发布的答案,他在其他方面似乎对他的知识非常慷慨并且在社区中很活跃,他说的是“简单。不要使用太多内存”。好的。告诉我怎么做。

我还应该提到 System.gc 对此没有任何帮助。我也知道 bitmap.recycle,但除非我弄错了,否则不能以这种方式使用它。

我错过了一些基本的东西吗?一旦不再使用图像数据,有没有办法丢弃它?上面缺少什么来创建一个简单的照片库?假设内置画廊应用程序使用框架而不是 NDK,我想必须有一种方法......

TYIA。

/这个问题也已经发布在android开发者google群列表中了。

【问题讨论】:

    标签: android


    【解决方案1】:

    通过我与Prime 的合作,我发现了一些技巧,其中一个你没有提到。当您解码您的位图时,请确保在您的BitmapFactory.Options 中使用inPurgeableinInputShareable 标志。这会有所帮助,但我建议您查看我在 Prime 中的图像加载实现。我在所有产品中都使用它,没有任何内存问题。我发现 95% 的内存问题都来自 Bitmap 类的错误使用。

    【讨论】:

    • 我发现大多数第 3 方加载器都强制使用 RGB_565 解码,这对于某些图像来说看起来有点糟糕……你的课程允许 ARGB_8888 吗?您是否有任何示例用法(除了一个 2-liner 之外,我在您的存储库中看不到任何示例 - 尽管 javadocs 很有帮助,但一些常见示例会很棒)。谢谢。
    • 我不强制格式化。示例位于标有“示例”的子文件夹中。它们也在 Google Play 上。
    • 我有兴趣使用您的课程,但有一些问题 - 您有扩展文档的计划吗?看起来没有侦听器机制(但我认为您可以扩展和覆盖 onImageReceived,这很好但不够灵活)。它看起来也仅限于 RemoteImageView,并且没有单独的加载机制(在为 ImageViews 以外的东西提供位图或可绘制时会很方便) - 我错过了一些东西吗?
    • 主要的api是使用ImageManager的Request接口,RemoteImageView只是一个方便集成的helper widget。
    • 类似 ImageManager.getInstance(context).get(new ImageManager.Request(){// overrides });
    【解决方案2】:

    android 开发者网站上有一个关于位图使用的非常detailed article。 你看了吗? 它解释了如何有效地加载、缓存和显示位图以及如何摆脱这个著名的 OutofMemoryError。

    还有来自图片库的a sample application。 我想这就是你要找的。​​p>

    【讨论】:

    • 我读过那篇文章/s - 它解释了如何使用大位图(不适用),如何在 UI 线程之外进行(我已经在做) ,如何缓存(不适用)以及如何在屏幕外渲染(已经在做)。同样,我可以使用“技巧”避免错误,但问题是“如何从内存中删除该图像”。感谢您的评论。
    猜你喜欢
    • 2011-11-07
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 2015-11-21
    • 2013-01-14
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    相关资源
    最近更新 更多