StreamBuilder
会在收到新事件时进行重建。例如,这会导致导航(Navigator.push
)问题,因为如果在导航时收到新事件,则会重新生成该触发器。由于尝试在仍在构建小部件树的同时进行导航,因此将抛出error。
not possible to prevent rebuild可以根据需要避免此问题。
建议的解决方法基本上是从cache开始的。 也: here和 here
但是,这还意味着StreamBuilder构建列表无法持续更新,如果还想提供列表中卡的导航功能。例如,在卡片onPressed()
中。 See here。
因此要刷新数据,必须使用拉动刷新...
有人有更好的解决方案吗? 还是Flutter团队正在努力解决此限制,例如通过在用户点击卡片时允许阻止重建来实现?
更新:
TL; DR是因为必须缓存StreamBuilder中的流以防止每次接收到新事件时重新生成数据,所以拉动刷新仅是更新数据的唯一方法吗?
更新2:
我已经尝试实现缓存数据,但是我的代码不起作用:
Stream<QuerySnapshot> infoSnapshot;
fetchSnapshot() {
Stream<QuerySnapshot> infoSnapshot = Firestore.instance.collection(‘info’).where(‘available’, isEqualTo: true).snapshots();
return infoSnapshot;
}
@override
void initState() {
super.initState();
fetchSnapshot();
}
...
child: StreamBuilder(
stream: infoSnapshot,
builder: (context, snapshot) {
if(snapshot.hasData) {
return ListView.builder(
itemBuilder: (context, index) =>
build(context, snapshot.data.documents[index]),
itemCount: snapshot.data.documents.length,
);
} else {
return _emptyStateWidget();
}
更新3:
我尝试使用StreamController
,但无法实现正确的方法:
Stream<QuerySnapshot> infoStream;
StreamController<QuerySnapshot> infoStreamController = StreamController<QuerySnapshot>();
@override
void initState() {
super.initState();
infoStream = Firestore.instance.collection(‘info’).where(‘available’, isEqualTo: true).snapshots();
infoStreamController.addStream(infoStream);
}
...
child: StreamBuilder(
stream: infoStreamController.stream,
builder: (context, snapshot) {
更新4:
使用_localStreamController
的建议给出了错误:
StreamController<QuerySnapshot> _localStreamController = StreamController<QuerySnapshot>();
@override
void initState() {
super.initState();
Firestore.instance.collection(‘info’).snapshots().listen((QuerySnapshot querySnapshot) {
// if(userAdded == null) {
_localStreamController.add(querySnapshot);
// }
});
...
child: StreamBuilder(
stream: _localStreamController.stream,
builder: (context, snapshot) {
getter'stream'在null上被调用。
调用了“添加”方法 空。
答案 0 :(得分:0)
基于以上评论,实际的问题似乎是在使用流导航离开视图后崩溃。您必须:
更新:添加带有伪示例的代码
class Widget {
// Your local stream
Stream<String> _localStream;
// Value to indicate if you have navigated away
bool hasNavigated = false;
...
void init() {
// subscribe to the firebase stream
firebaseStream...listen((value){
// If this value is still false then emit the same value to the localStream
if(!hasNavigated) {
_localStream.add(value);
}
});
}
Widget build() {
return StreamBuilder(
// subscribe to the local stream NOT the firebase stream
stream: _localStream,
// handle the same way as you were before
builder: (context, snapshot) {
return YourWidgets();
}
);
}
}
答案 1 :(得分:0)
尝试将所有内容分解为小部件
即使您完全关闭应用程序,运行查询也应将其缓存(我相信仅在完全关闭的情况下才将其缓存长达30分钟,但是如果您仍未连接互联网,则您仍可以从 Firestore )
尝试这样的事情:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Please work')),
body: _buildStream(context),
);
}
Widget _buildStream(BuildContext context) {
return StreamBuilder(
stream: yourFireStoreStream,
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildAnotherwidget(context, snapshot.data.documents);
},
);
}
Widget _buildAnotherwidget(Buildcontext context, List<DocumentSnapshot> snaps){
return ListView.Builder(
itemCount: snaps.length,
itemBuilder:(context, index) {
..dostuff here...display your cards etc..or build another widget to display cards
}
);
}
专注于分解成更多的小部件。最高的部分应该具有streambuilder和流。然后深入了解更多小部件。 streambuilder会自动侦听并订阅给定的流。
streambuilder更新时,它将更新下部的窗口小部件。
现在,以这种方式,当您点击下部小部件中的卡进行导航时,它不会影响最高的小部件,因为它只会影响UI。
我们将streambuilder放置在其自己的顶级小部件中...
我希望我有道理:(
我写出的代码未经测试,但我确定您可以使它正常工作