【问题标题】:Flutter StreamBuilder Produces Snapshots From Previous Generator StreamFlutter StreamBuilder 从先前的生成器流生成快照
【发布时间】:2021-02-07 14:35:33
【问题描述】:

我有一个 StreamBuilder 包装在另一个 StreamBuilder 中。内部 StreamBuilder 将分页异步查询的结果加载到 ListView 中。外部 StreamBuilder 使用用户指定的搜索文本发出一个新查询,并构建一个新的内部 StreamBuilder 来监听新查询。该查询使用生成器函数生成流。

我注意到一些非常奇怪的行为: 当发出新查询并使用新 Stream 重建内部 StreamBuilder 时,它最初会从前一个 Stream 接收数据。这在新 Stream 为空时尤其明显(例如,用户的查询没有产生任何结果)。如果新的 Stream 为空,它将从 ConnectionState.waiting 变为 ConnectionState.done,并且(我认为错误地)两个事件都填充了来自先前生成器 Stream 的数据。

这是我编写的一些代码,用于以尽可能孤立的方式重现这一点。为简单起见,我将外部 StreamBuilder 替换为 FutureBuilder,尽管行为相同。

import 'dart:async';

import 'package:flutter/material.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final Future<bool> oneSecondFuture = Future.delayed(Duration(seconds: 2), () {
    print('future completed!');
    return true;
  });

  @override
  Widget build(BuildContext context) {
    Stream<int> intStream(bool returnValues) async* {
      var lst = [1, 2, 3];
      var i = 0;
      while (returnValues) {
        if (i == lst.length) break;
        yield lst[i++];
        await Future.delayed(Duration(milliseconds: 40));
      }
    }

    print('building');
    var futureBuilder = FutureBuilder(
      future: oneSecondFuture,
      builder: (_, boolSnap) {
        // If the future isn't complete yet, return a StreamBuilder with a nonempty stream
        if (!boolSnap.hasData) return StreamBuilder(
            stream: intStream(true),
            builder: (_, intSnap) {
              print('Nonempty steambuilder: ' + intSnap.connectionState.toString() + '; ' + intSnap.data.toString());
              return Text(intSnap.data.toString());
            }
        );

        // If the future is complete, return a StreamBuilder with an empty stream
        return StreamBuilder(
            stream: intStream(false),
            builder: (_, intSnap) {
              print('Empty steambuilder: ' + intSnap.connectionState.toString() + '; ' + intSnap.data.toString());
              return Text(intSnap.data.toString());
            }
        );
      }
    );

    return MaterialApp(
      title: 'Test StreamBuilder',
      home: futureBuilder,
    );
  }
}

以上代码产生以下打印输出:

I/flutter (20225): building
I/flutter (20225): Nonempty streambuilder: ConnectionState.waiting; null
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 1
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 2
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 3
I/flutter (20225): Nonempty streambuilder: ConnectionState.done; 3
I/flutter (20225): building
I/flutter (20225): Nonempty streambuilder: ConnectionState.waiting; 3
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 1
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 2
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 3
I/flutter (20225): Nonempty streambuilder: ConnectionState.done; 3
I/flutter (20225): future completed!
I/flutter (20225): Empty streambuilder: ConnectionState.waiting; 3
I/flutter (20225): Empty streambuilder: ConnectionState.done; 3

请注意,在等待连接时,第二个构建从最后一个流的值“3”开始。空流为 waiting 和 done 事件生成 3 值。

如果我创建第二个相同的 intStream 函数(即 intStream 和 intStreamTwo)并在未来完成后调用它,我会按预期获得空数据值,因此问题似乎源于重复调用单个生成器函数以获取不同的流:

I/flutter (20225): building
I/flutter (20225): Nonempty streambuilder: ConnectionState.waiting; null
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 1
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 2
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 3
I/flutter (20225): Nonempty streambuilder: ConnectionState.done; 3
I/flutter (20225): building
I/flutter (20225): Nonempty streambuilder: ConnectionState.waiting; 3
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 1
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 2
I/flutter (20225): Nonempty streambuilder: ConnectionState.active; 3
I/flutter (20225): Nonempty streambuilder: ConnectionState.done; 3
I/flutter (20225): future completed!
I/flutter (20225): using a different generator function:
I/flutter (20225): Empty streambuilder: ConnectionState.waiting; null
I/flutter (20225): Empty streambuilder: ConnectionState.done; null

这是预期的行为吗?有没有一种理智的方法可以让 StreamBuilder 不从以前的生成器 Stream 接收数据?我想我可以创建两个相同的生成器函数并在它们之间交替,但我真的想要一个不那么 hacky 的解决方案。

【问题讨论】:

    标签: flutter dart generator stream-builder dart-stream


    【解决方案1】:

    通过更仔细地阅读文档,我已经回答了我自己的问题。这似乎是(令人难以置信的混乱)预期行为。见documentation

    但是,我仍然不清楚为什么使用来自同一生成器函数的新流会触发此行为,而使用来自不同生成器函数的新流不会。

    无论哪种方式,对于面临相同问题的任何其他人,我的预期解决方法是在 ConnectionState 为“等待”或“完成”时忽略错误的数据值,只要流为空(例如“ done' 的快照是在没有收到有效事件值的情况下收到的)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-29
      • 2021-12-29
      • 2022-08-24
      • 2016-12-02
      • 2021-07-01
      • 2023-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多