Flutter StreamBuilder从先前的生成器流中生成快照

时间:2020-10-24 22:05:40

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

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

我注意到一些非常奇怪的行为: 发出新查询并用新Stream重建内部StreamBuilder时,它最初会从先前的Stream接收数据。当新的Stream为空时(例如,用户的查询未产生结果),这一点尤其明显。如果新的Stream为空,则它从ConnectionState.waitingConnectionState.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”开始。空流在等待事件和完成事件中产生的值为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的数据的明智方法?我想我可以创建两个相同的生成器函数并在它们之间交替,但是我真的很想在这里找到一个不太麻烦的解决方案。

1 个答案:

答案 0 :(得分:0)

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

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

无论哪种方式,对于其他面临相同问题的其他人,我打算解决的方法是,当ConnectionState为“ waiting”或“ done”时,只要流为空(例如,“ “完成”快照,而不会收到有效的事件值。