我有一个列表,显示从网上实时下载的缩略图(小图片)。
但是在某个时刻,这个过程会耗尽内存。
我该如何判断可用内存即将耗尽,以便停止下载更多的图片?
我希望提前知道这一点,以免处于内存不足的边缘。
注意: 这不是内存泄漏,只是下载了大量的位图。
谢谢。
我有一个列表,显示从网上实时下载的缩略图(小图片)。
但是在某个时刻,这个过程会耗尽内存。
我该如何判断可用内存即将耗尽,以便停止下载更多的图片?
我希望提前知道这一点,以免处于内存不足的边缘。
注意: 这不是内存泄漏,只是下载了大量的位图。
谢谢。
1) 自己做浏览器。
将缩略图下载到SD卡,而不是保存在RAM中。在保存它们之前缩小/旋转它们,以便在下次加载它们时,从SD卡而不是互联网加载是“免费”的。(即像任何浏览器一样,使用本地文件缓存)。
释放任何你可能创建来执行此操作的临时 Bitmap 对象。
学习如何使用 "inSampleSize
" 参数解压缩低于原始分辨率的位图。
如果你写的文件以图像扩展名结尾(.jpg等),它们将出现在图库中,因此不要用明显的图像文件名保存缩略图。
2) 创建分层缓存系统(Bitmap > SD卡 > 互联网)。
当你解压缩缩略图时,将其保存在 SoftReference 缓存中。如果你需要使用该缩略图,请从缓存中获取它。如果 VM 需要更多内存,则你的 SoftReference 实例可能返回 null。
如果从位图缓存中获取到 null,则检查是否已将 URL 放在 SD 卡上,并从那里加载到位图缓存中。
如果从文件系统中获取 null,则从互联网下载图像并将其保存到SD卡中,然后将其放入位图缓存中。
3) 释放不再使用的资源。
同样地,确保在 View 不再显示时就从它们所放置的 Bitmaps 中清除它们(如果你的 Views 存在于 ListView 或其他基于 Adapter 的元素中,这基本上是从回收 View 元素中“免费”完成的)-- 然而,如果你实例化了带有 Bitmaps 的 ImageView,并且它们不立即显示在屏幕上,那么你可能会浪费堆空间。
你可以简单地在 ImageView 上调用 setImageBitmap(null);
,这样对于 Bitmap 的引用将被删除(因此,如果唯一的引用是 SoftReference,当它不被使用时,它将被回收)。
4) 注意你处于哪个线程。
记住,你必须从非 UI 线程下载位图(我们使用 Service 实例作为意图请求的队列),并且你必须仅在 UI 线程中将位图附加到 View 实例中。
你需要创建一个良好的排队系统,以从 UI 线程之外的所有内容加载到位图缓存中,然后使用 Handler 告诉你的位图缓存在 UI 线程上填充 ImageView。
5) 注意你的下载队列。
如果像我们一样,你有缩略图和全尺寸图像,你需要手动使用优先级队列将图像请求放在缩略图请求之前,或者使用两个不同的 Service(它们分别将它们的独立意向排队)来下载缩略图与完整图片。
否则,你可能会对一屏幕缩略图下载进行排队,但直到所有缩略图都完成后才响应完整图像。
6) 向系统询问你有多少RAM。
Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memoryInfo);
7) "onLowMemory()
" 方法并不会如你所想的那样。
它是用于当用户在手机上运行太多应用程序,操作系统需要从所有正在运行的应用程序中恢复物理内存时使用的。
这与由于加载过多位图而轻松耗尽应用程序 VM 堆完全不同。
据我所知,您将不会收到警告,您将只会崩溃(但您可以使用上述调用跟踪内存信息)。
希望这对尝试智能下载和显示来自互联网的缩略图有所帮助。
mig
我使用SoftReference来保存位图对象。列表只需要当前可见的图像。因此,我永远不需要担心空间不足。
缺点是,当我查看图像并向下滚动(导致某些SoftReferences清除位图),然后再次滚动回到同一位置时,图像会再次下载 :(
此外,SoftReferences被清除得非常快。我希望它们能更长时间地保存内部位图。
在创建位图时,您应该使用BitmapFactory.Options
的inSampleSize
选项。
此外,在Android:相册中内存不足异常中的一些提示对我有所帮助,可以检查可用内存。
你可以重写 Activity 的 onLowMemory()
方法来处理这种情况的自定义操作。