列表视图中的图像在视图外时不会从内存中释放
Images in listview are not released from memory when out of view
我正在垂直显示来自 Internet 的图像 ListView
。我使用 http.get
获取图像(不使用缓存的网络图像,因为我不想缓存图像)。然后我将图像 Uint8List
插入到 image.memory()
中。发生的事情是,当用户滚动列表并加载图像时,ram 会不断增加,直到整个应用程序崩溃。有什么想法吗?
是的,这是正常行为。我不知道为什么。我的理论是,如果保存对它们的引用的飞镖对象被垃圾收集,而不是当小部件从小部件树中删除时,默认情况下图像将被处理,但不要相信我的话 - 这只是我个人的推理。这可能是完全错误的。
为了解决这个问题,我使用 Extended Image pakcage 它的构造函数采用 bool clearMemoryCacheWhenDispose
来处理滚动列表中 RAM 中的图像。你可以这样做或者访问包代码看看他是怎么做的,然后复制它。
我可以提供的其他建议是确保您的图片尺寸合适。如果您在本地加载图像,请检查文档的这一部分以针对不同的屏幕尺寸选择不同的尺寸 https://flutter.dev/docs/development/ui/assets-and-images#loading-images
如果您更有可能从网络获取图片,请确保它们的尺寸合适,如果可以的话,提供不同尺寸的图片。如果您无法控制 cacheWidth
和 Image.memory
中的 cacheHeight
,这些将减少内存 (RAM) 中的缓存图像。 您会看到默认情况下 Flutter 以全分辨率缓存图像,尽管它们在 device/app 中的表观尺寸。例如,如果您希望您的图像显示在 200x200 框中,则将 cacheWidth
设置为 200 * window.devicePixelRatio.ceil()
您将在 dart:ui
中找到 window
,如果您只设置 cacheWidth
,您的图像比例将保持真实。如果您只设置 cacheHeight
,也是如此。也请按照建议使用 ListView.builder
。
我很失望在 Flutter 文档中对此很少提及。大多数时候,人们会在应用程序开始崩溃时发现这个问题。 请定期检查您的开发工具的内存消耗情况。这是最好的指标。
干杯,祝你好运
我从 ListView 中的文件加载图像时遇到了类似的问题。
[left-side:旧代码,right-side:新代码]
我的第一个巨大改进:不要一次加载整个列表
ListView(children:[...])
---> ListView.builder(...)
.
第二个改进是图像不再加载到 full-size:
Image.file("/path")
---> Image.file("/path", cacheWidth: X, cacheHeight: Y)
这两件事彻底解决了我的记忆问题
理想情况下,缓存会在满足某些条件后默认发生。因此,由您的应用负责处理和控制缓存的发生方式。
签出这个答案
我遇到了同样的问题,感谢@moneer 找到了解决方法!
上下文:
我的应用程序中的用户可以创建可以轻松包含数百张图片的共享图片库。这些都显示在 SliverGrid 小部件中。当用户向下滚动列表时,太多图像被加载到 RAM 中,应用程序会崩溃。
我已经实现的东西:
- 在服务器端调整图像大小,并根据设备像素比和图库中的图块大小在客户端获取适当大小的图像
- 我确保我的图像小部件在不可见时被正确处理,但是随着用户滚动浏览所有图像,内存大小不断增加
- 实施 cacheHeight 以将缓存图像的大小限制为显示图像的确切大小
所有这些都有帮助,但每次用户向下滚动足够远时,应用程序最终仍会崩溃。
修正:
经过一些谷歌搜索后,我偶然发现了这个线程,并按照@moneer 的建议尝试了 extended_image_package。将 clearMemoryCacheWhenDispose
标志设置为 true 解决了应用程序崩溃的问题,因为它现在可以在图像不在视图中时从内存中正确清除图像。万岁!但是,在我的应用程序中,用户可以点击图像,然后应用程序会导航到带有漂亮英雄动画的图像详细信息页面。当导航回来时,图像将重建,这将导致重建 'flicker'。不太好看,有点让人分心。
然后我注意到还有一个 enableMemoryCache
标志。我尝试将其设置为 false,这似乎对我来说效果很好。 Dart DevTools 中的“网络”选项卡似乎显示,当多次上下滚动画廊时,所有图像仅从网络中获取一次。该应用程序不再崩溃。
我将不得不进行更多测试,看看这是否会导致任何性能问题(如果您能想到任何问题,请告诉我)。
最终代码:
ExtendedImage.network(
_imageUrl,
cacheHeight: _tileDimension,
fit: BoxFit.cover,
cache: true, // store in cache
enableMemoryCache: false, // do not store in memory
enableLoadState: false, // hide spinner
)
我正在垂直显示来自 Internet 的图像 ListView
。我使用 http.get
获取图像(不使用缓存的网络图像,因为我不想缓存图像)。然后我将图像 Uint8List
插入到 image.memory()
中。发生的事情是,当用户滚动列表并加载图像时,ram 会不断增加,直到整个应用程序崩溃。有什么想法吗?
是的,这是正常行为。我不知道为什么。我的理论是,如果保存对它们的引用的飞镖对象被垃圾收集,而不是当小部件从小部件树中删除时,默认情况下图像将被处理,但不要相信我的话 - 这只是我个人的推理。这可能是完全错误的。
为了解决这个问题,我使用 Extended Image pakcage 它的构造函数采用 bool clearMemoryCacheWhenDispose
来处理滚动列表中 RAM 中的图像。你可以这样做或者访问包代码看看他是怎么做的,然后复制它。
我可以提供的其他建议是确保您的图片尺寸合适。如果您在本地加载图像,请检查文档的这一部分以针对不同的屏幕尺寸选择不同的尺寸 https://flutter.dev/docs/development/ui/assets-and-images#loading-images
如果您更有可能从网络获取图片,请确保它们的尺寸合适,如果可以的话,提供不同尺寸的图片。如果您无法控制 cacheWidth
和 Image.memory
中的 cacheHeight
,这些将减少内存 (RAM) 中的缓存图像。 您会看到默认情况下 Flutter 以全分辨率缓存图像,尽管它们在 device/app 中的表观尺寸。例如,如果您希望您的图像显示在 200x200 框中,则将 cacheWidth
设置为 200 * window.devicePixelRatio.ceil()
您将在 dart:ui
中找到 window
,如果您只设置 cacheWidth
,您的图像比例将保持真实。如果您只设置 cacheHeight
,也是如此。也请按照建议使用 ListView.builder
。
我很失望在 Flutter 文档中对此很少提及。大多数时候,人们会在应用程序开始崩溃时发现这个问题。 请定期检查您的开发工具的内存消耗情况。这是最好的指标。
干杯,祝你好运
我从 ListView 中的文件加载图像时遇到了类似的问题。
[left-side:旧代码,right-side:新代码]
我的第一个巨大改进:不要一次加载整个列表
ListView(children:[...])
--->ListView.builder(...)
.
第二个改进是图像不再加载到 full-size:
Image.file("/path")
--->Image.file("/path", cacheWidth: X, cacheHeight: Y)
这两件事彻底解决了我的记忆问题
理想情况下,缓存会在满足某些条件后默认发生。因此,由您的应用负责处理和控制缓存的发生方式。 签出这个答案
我遇到了同样的问题,感谢@moneer 找到了解决方法!
上下文:
我的应用程序中的用户可以创建可以轻松包含数百张图片的共享图片库。这些都显示在 SliverGrid 小部件中。当用户向下滚动列表时,太多图像被加载到 RAM 中,应用程序会崩溃。
我已经实现的东西:
- 在服务器端调整图像大小,并根据设备像素比和图库中的图块大小在客户端获取适当大小的图像
- 我确保我的图像小部件在不可见时被正确处理,但是随着用户滚动浏览所有图像,内存大小不断增加
- 实施 cacheHeight 以将缓存图像的大小限制为显示图像的确切大小
所有这些都有帮助,但每次用户向下滚动足够远时,应用程序最终仍会崩溃。
修正:
经过一些谷歌搜索后,我偶然发现了这个线程,并按照@moneer 的建议尝试了 extended_image_package。将 clearMemoryCacheWhenDispose
标志设置为 true 解决了应用程序崩溃的问题,因为它现在可以在图像不在视图中时从内存中正确清除图像。万岁!但是,在我的应用程序中,用户可以点击图像,然后应用程序会导航到带有漂亮英雄动画的图像详细信息页面。当导航回来时,图像将重建,这将导致重建 'flicker'。不太好看,有点让人分心。
然后我注意到还有一个 enableMemoryCache
标志。我尝试将其设置为 false,这似乎对我来说效果很好。 Dart DevTools 中的“网络”选项卡似乎显示,当多次上下滚动画廊时,所有图像仅从网络中获取一次。该应用程序不再崩溃。
我将不得不进行更多测试,看看这是否会导致任何性能问题(如果您能想到任何问题,请告诉我)。
最终代码:
ExtendedImage.network(
_imageUrl,
cacheHeight: _tileDimension,
fit: BoxFit.cover,
cache: true, // store in cache
enableMemoryCache: false, // do not store in memory
enableLoadState: false, // hide spinner
)