在ListView中显示图像时内存不足 [英] Out of memory when displaying images in ListView

查看:166
本文介绍了在ListView中显示图像时内存不足的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,所以我想从LinearView中获取项目并获得它们的可见性,以便释放隐藏项目上的内存。

Ok, so I want to get items from LinearView and get their visibility, so I can free memory on the hidden items.

是否可以做到这一点?
还有其他想法吗?

Is it possible to do that? Do you have any other ideas?

因此,基本上,我想显示从URL动态下载的图像流,我希望它们位于一个ListView,因此该人员可以滚动浏览它们,但是如果我们仅使用像这样的常规生成器加载ListView,

So basically, I want to show a stream of images being dynamically downloaded from URLs, I want them to be in a ListView, so the person can scroll through them, but if we just load the ListView with a normal builder like this,

ListView lvb = new ListView.builder(
    cacheExtent: 1.0,
    itemBuilder: (BuildContext context, int index) {
      return new ImageView(MyApp.imageLinks.values.elementAt(index));
    },
);

它会立即下载所有项目,并且设备内存不足。所以我在想,我只是释放图像占用的内存,然后允许用户加载更多图像而不必担心内存。

it'd download all items at once and the device would run out of memory. So I was thinking that I'd just free the memory taken up by image and then allow user to load more images without having to worry about memory.

另外,我d一次只希望加载5张图像,因此将显示1张,上方显示2张,下方显示2张,以便更快更流畅地滚动。

Also, I'd like to only have 5 images loaded at a time, so 1 would be displayed, 2 above and 2 below for faster and more fluid scrolling.

我的问题:


  • 有没有办法确定是否绘制(在视图中)?

  • 我可以吗?限制我要在LinearView中拥有多少ImageView,但要保持滚动能力。

编辑:如所承诺的ImageView类

ImageView class as promised

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开始列出项目,它就会开始向控制台发送已创建新图像的垃圾邮件。

As soon as the ListView starts to list items, it starts spamming "New image created" into the console.

推荐答案

我将以不回答的方式回答。从理论上讲,可以使用Slivers和CustomScrollView或使用自定义RenderObjects来确定是否绘制项目,但是我认为这并不是您真正想要的。

I'm going to answer this with a non-answer. It is theoretically possible to determine whether the item is drawn or not using Slivers and a CustomScrollView or possibly by using custom RenderObjects, but I don't think that's what you actually want.

除非您对图像做一些奇怪的事情编辑:请参阅,但使用ListView.builder可以防止您描述的精确情况。

Unless you're doing something weird with your images SEE END, using the ListView.builder is designed to protect against the exact scenario you're describing.

ListView.builder的文档(重点是我的文档):

From the first line of the documentation for ListView.builder (emphasis mine):


创建一个可滚动的线性数组,这些数组是按需创建

使用ListView.builder而不是新ListView的想法([items] )是它应该自动处理您在说的内容-仅创建当前可见的元素。

The idea of using ListView.builder as opposed to new ListView([items]) is that it should automatically handle exactly what you're talking about - creating only the currently visible elements.

如果您已顺其自然,您实际上是在真实设备上用完了内存,那么这是与Flutter人员= D一起引发错误的好例子。

If you've implemented this and you are actually running out of memory on a real device, then that would be a good case for raising a bug with the Flutter people =D.

此外,将 cacheExtent 设置为1.0实际上会降低性能。从 cacheExtent文档

Also, setting cacheExtent to 1.0 will actually be worse for performance. From the cacheExtent docs:


视口在可见区域之前和之后都有一个区域,用于缓存当用户滚动时将变得可见的
项。

The viewport has an area before and after the visible area to cache items that are about to become visible when the user scrolls.

即使尚未在屏幕上显示
,落入此缓存区域的项目也会被布局。 cacheExtent描述了缓存区域在视口的前边缘之前和后边缘
之前扩展了多少像素

Items that fall in this cache area are laid out even though they are not (yet) visible on screen. The cacheExtent describes how many pixels the cache area extends before the leading edge and after the trailing edge of the viewport.

通过将该值设置为1.0,就可以使它离开视口后立即将其重新分配。而且下一张图片要等到视图清晰时才能加载。因此,下次滚动(向后或向前)时,(下一个或最后一个)图像将必须在显示时加载。

By setting that to 1.0, you're making it so that as soon as a picture is out of the viewport, it's being deallocated. And that the next images don't load until they're pretty much in view. So next time you scroll (back or forward), the (next or last) image will have to load as it's coming into view.

如果将其设置得更高(或将其保留为默认值(当前为250.0)),您可以进行设置,以便完全根据需要加载下一张图片。

If you set this higher (or leave it to the default which is currently 250.0) you can make it so that the next images will load ahead of time, exactly as you want.

编辑:

因此,这里还有其他因素在起作用。感谢您发布ImageView代码。

So there's an additional factor at work here. Thanks for posting your ImageView code.

问题是您使用的是FractionallySizedBox,它的widthFactor却没有HeightFactor。您将宽度设置为1.0,但没有设置高度(无论如何都无法工作),因此它占用的空间为零,因此会一直尝试永久加载图像。

The issue is that you're using a FractionallySizedBox with a widthFactor but no HeightFactor. You're setting width to 1.0, but no height (which wouldn't work anyways), so it's taking up zero space and therefore keeps trying to load images forever.

最好的选择是使用SizedBox,ConstrainedBox或AspectRatio为图像指定高度,然后包含封面

Your best bet to specify a height using a SizedBox, ConstrainedBox, or AspectRatio for your images and then either contain or cover with the fit option for Image.network.

这是一个有趣的示例-无限加载dogs =)

Here's a fun example - infinitely loading 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,
      ),
    );
  }
}

这篇关于在ListView中显示图像时内存不足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆