【问题标题】:How to display phone gallery images to my grid view如何将手机图库图像显示到我的网格视图
【发布时间】:2018-08-24 05:31:42
【问题描述】:

事实上,这在某种程度上是一个理论上的问题,因为我确实做到了这一点,但是由于加载了我手机中存在的所有图像而导致内存中断。以下是我将图像存储到列表中的方式。

final Directory extDir = await getExternalStorageDirectory();

extDir.list(recursive: true, followLinks: false)
  .listen((FileSystemEntity entity) {
    print(entity.path);

    /* check for image and save */
    if(entity.path.endsWith("jpg")
    || entity.path.endsWith("png")
    || entity.path.endsWith("gif")
    ) {
      _PhoneImages.add(entity.path);
    }...

所以,我拉出列表中的路径并在我的网格视图中显示如下..

new GridView.count(
              shrinkWrap: true,
              physics: new ClampingScrollPhysics(),
              crossAxisCount: 2,

              children: new List<Widget>.generate(_PhoneImages.length, (index) {
                return new GridTile(
                  child: new GestureDetector(
                      child: new Stack(
                        children: [

                          new Card(
                            color: Colors.blue.shade200,
                            child: new Center(


                              child: new Image.file(
                                new File(_PhoneImages[index]),
                              ),
                            ),...

这确实显示了前几张图片,但会慢慢崩溃,并在“运行”控制台中显示以下内容

Lost connection to device

我必须重新开始。但当然,它在尝试加载时会做同样的事情。我在这里做错了什么?

【问题讨论】:

    标签: gridview memory-leaks flutter


    【解决方案1】:

    这里有几件事会导致问题。

    1. 您正在使用收缩包装,听起来像是大量的对象。
    2. 您使用的是 Gridview.count 而不是构建器
    3. 您的图片没有预定义的高度

    我将解释为什么这些都是一个坏主意:

    1) 使用收缩包装:

    正如文档中所说,Shrinkwrap 是:

    scrollDirection 中滚动视图的范围是否应该是 由正在查看的内容决定。

    一个简单的例子来解释这一点,如果您的网格应该占据整个屏幕,但其中只有 2 个项目。如果您启用了 ShrinkWrap,则网格将只占用与这两个项目相同的空间;如果关闭收缩包装,它将占据整个屏幕,但项目仍将位于顶部。

    不同之处在于,启用 ShrinkWrap 后,GridView 必须在每次滚动时计算其子级的高度,以确保最大高度没有改变。

    大多数情况下,您不希望使用 ShrinkWrap,除非您有特定的用例(即,每次删除项目时,您都希望在其下方带有删除按钮的网格向上移动)。您绝对不希望将 ShrinkWrap 与大量项目一起使用,因为这意味着网格需要对每个项目进行布局,然后才能确定列表的最大范围。

    2) 使用 GridView.count:

    通过使用count 类型构造函数之一,网格视图将立即构建(至少部分)列表中的每个项目。 As it says in the docs:

    要创建具有大量(或无限)子节点的网格,请使用 GridView.builder 构造函数 SliverGridDelegateWithFixedCrossAxisCount 或 gridDelegate 的 SliverGridDelegateWithMaxCrossAxisExtent。

    通过这样做,它允许 gridview 仅实例化屏幕上的那些项目(如果您设置了 cacheExtent,则在每一侧都缓存一点)。

    3) 没有预定义的高度:

    这是一个常见的错误。因为网格中的每个项目都没有特定的大小,所以他们委托给他们的孩子来找到一个大小。但是,由于图像在加载之前没有大小,这可能会导致问题。

    基本上,每张图片的起始高度都接近于零。这意味着屏幕上可以容纳很多很多图像,因此手机会尝试加载所有图像。这可能是导致您的内存问题和崩溃的原因。

    我建议设置网格图块的大小或至少设置纵横比,以便它们可以立即确定它们的高度。如果需要,您可以让它们在图像加载后委托给图像的大小,但最好对每个图像简单地使用 BoxFit。

    【讨论】:

    • 感谢您的解释,这是很棒的一课。然而,我确实使用了固定高度,并且还使用了特定尺寸的 boxfit。我认为可能是收缩包装或项目本身的大小导致内存过载。我找到了一种使用 Image 包调整大小的方法,它们现在看起来很好,没有崩溃,但只是暂时的。我使用收缩包装的原因是因为我在页面视图中使用网格视图。此当前网格位于第二页。
    • 在这种情况下,我认为您仍然不需要收缩包装,除非您正在做一些奇怪的事情。页面视图水平滚动,而网格垂直滚动(至少默认情况下),收缩包装只影响网格滚动的方向。如果网格和浏览量都是相同的方向,那么情况就不同了。无论如何,如果您设置了收缩包装、使用计数或图像没有高度,您将遇到问题 - 您需要修复所有这三个。
    • 如果你添加了足够多的代码来运行这个例子,我可以试一试。
    猜你喜欢
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多