好吧,所以我想从LinearView中获取项目并获得其可见性,以便释放隐藏项目上的内存。
有可能这样做吗? 您还有其他想法吗?
因此,基本上,我想显示从URL动态下载的图像流,我希望它们位于ListView中,以便该人员可以滚动浏览它们,但是如果我们仅使用像这样的常规构建器加载ListView ,
ListView lvb = new ListView.builder(
cacheExtent: 1.0,
itemBuilder: (BuildContext context, int index) {
return new ImageView(MyApp.imageLinks.values.elementAt(index));
},
);
它将立即下载所有项目,并且设备将耗尽内存。所以我在想,我只是释放图像占用的内存,然后允许用户加载更多图像而不必担心内存问题。
此外,我想一次只加载5张图像,因此将显示1张,上方显示2张,下方显示2张,以实现更快更流畅的滚动。
我的问题:
编辑:承诺的ImageView类
class ImageView extends StatelessWidget {
String url;
ImageView([String url]) {
if (url != null) {
this.url = url;
}
print("New image");
}
@override
Widget build(BuildContext context) {
FractionallySizedBox fsb;
if (url != null) {
Image el = Image.network(
url,
scale: 0.1,
);
fsb = new FractionallySizedBox(
widthFactor: 1.0,
child: el,
);
print("New image created");
return fsb;
}
}
ListView一旦开始列出项目,就会开始向控制台发送“创建新图像”的垃圾邮件。
答案 0 :(得分:2)
我将以不回答的方式回答。从理论上讲,可以使用Slivers和CustomScrollView或通过使用自定义RenderObjects来确定是绘制项目还是不绘制项目,但我认为这并不是您真正想要的。
除非您对图像做一些奇怪的事情,请使用ListView.builder来防止您描述的 exact 场景。
从documentation for ListView.builder(强调我的名字)的第一行开始:
创建可滚动的线性小部件数组,这些小部件是按需创建的 。
使用ListView.builder而不是新的ListView([items])的想法是,它应自动处理您正在谈论的内容-仅创建当前可见的元素。
如果您已实现此功能,而实际上是在真实设备上用尽了内存,那么这是向Flutter人员= D提出错误的好例子。
此外,将cacheExtent
设置为1.0实际上会降低性能。来自cacheExtent docs:
视口在可见区域前后都有一个要缓存的区域 用户滚动时将变为可见的项目。
落入此缓存区域的项目即使它们是 在屏幕上尚未显示。 cacheExtent描述多少像素 缓存区在前沿之前和之后延伸 视口的边缘。
通过将其设置为1.0,就可以使它离开视口后立即被释放。而且下一个图像要等到视图很清晰才加载。因此,下次滚动(向后或向前)时,(下一个或最后一个)图像必须在其进入视图时加载。
如果将此值设置得较高(或将其设置为当前的默认值250.0),则可以进行设置,以使下一幅图像可以完全根据您的需要提前加载。
编辑:
因此,这里还有其他因素在起作用。感谢您发布ImageView代码。
问题是您正在使用带有widthFactor但没有HeightFactor的FractionallySizedBox。您将宽度设置为1.0,但没有设置高度(无论如何都无法工作),因此它占用的空间为零,因此会一直尝试永久加载图像。
最好的选择是使用SizedBox,ConstrainedBox或AspectRatio为图像指定高度,然后为contain
或cover
使用Image.network的fit
选项。
这是一个有趣的示例-无限加载dogs =)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: Text("Title"),
),
body: ListView.builder(
cacheExtent: 1000.0,
itemBuilder: (BuildContext context, int index) {
return new ImageView(
num: index,
url: "https://loremflickr.com/640/480/dog?random=$index",
);
},
),
),
);
}
}
class ImageView extends StatelessWidget {
final int num;
final String url;
ImageView({@required this.num, @required this.url});
@override
Widget build(BuildContext context) {
print("Building image number $num");
return new AspectRatio(
aspectRatio: 3.0 / 2.0,
child: Image.network(
url,
fit: BoxFit.cover,
),
);
}
}
答案 1 :(得分:0)
我知道这是一个老话题,但仍然与我相关,我没有发现这些答案中的任何一个真正有效,并且提到的插件/小部件并没有真正提供很大的灵活性。我最终找到了小部件 photo_gallery
它足够灵活,可以加载特定专辑而不是所有专辑,并且 ThumbnailProvider 可以生成出色的图像而不会占用太多内存。我在 GridView 的同一页面上加载了多达 50 个 1+MB 的文件。
我不会在这里添加任何代码,因为 repo 中的示例就是您所需要的。我给您的唯一建议是设置 ThumbnailProvider 的宽度和高度。默认为 72x72,这些天相当低。我在旧的 Nexus 6 上使用了 256x256,没有任何内存问题。抱歉,我不能说 iOS 设备。