Flutter StreamBuilder从以前的生成器流生成快照



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

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

下面是我写的一些代码,以尽可能孤立的方式复制它。为了简单起见,我用FutureBuilder替换了外部StreamBuilder,尽管行为是相同的。

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接收数据?我想我可以创建两个相同的生成器函数并在它们之间交替,但我真的希望这里有一个不那么棘手的解决方案。

我通过仔细阅读文档回答了自己的问题。这似乎是(令人难以置信的困惑(有意的行为。请参阅文档。

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

无论哪种方式,对于其他面临相同问题的人,我打算解决的问题是,当ConnectionState"等待"或"完成"时,只要流为空,就忽略错误的数据值,并使用一些额外的逻辑(例如,在从未接收到有效事件值的情况下接收到"完成"快照(。

最新更新