我有一个 StreamBuilder 包裹在另一个 StreamBuilder 中。内部 StreamBuilder 将分页异步查询的结果加载到 ListView 中。外部 StreamBuilder 使用用户指定的搜索文本发出一个新查询,并构建一个新的内部 StreamBuilder 来监听新查询。该查询使用生成器函数生成流。
我注意到一些非常奇怪的行为:当发出一个新查询并使用新 Stream 重建内部 StreamBuilder 时,它最初从前一个 Stream 接收数据。这在新 Stream 为空时尤其明显(例如,用户的查询没有产生任何结果)。如果新的 Stream 是空的,它会从ConnectionState.waiting
to 开始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 接收数据?我想我可以创建两个相同的生成器函数并在它们之间交替,但我真的想要一个不那么老套的解决方案。