首页 > 解决方案 > StreamBuilder 限制

问题描述

StreamBuilder每当它获得新事件时都会重建。这会导致例如导航 ( Navigator.push) 出现问题,因为如果在导航时接收到新事件,则此触发器会重建。因为在小部件树仍在构建时尝试导航,这将抛出错误

无法根据需要阻止重建以避免此问题。

建议的解决方法基本上是从缓存中获取流。另外: 这里这里

但这意味着如果还想从列表中的卡片提供导航,则不能让 StreamBuilder 构建列表不断更新。例如在卡片中onPressed()见这里

所以刷新数据必须使用pull来刷新……</p>

有人有更好的解决方案吗?或者 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);
  }

…</p>

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) {

在 null 上调用了 getter 'stream'。

在 null 上调用了方法“add”。

标签: dartflutterfuturestream-builderflutter-navigation

解决方案


根据您上面的评论,实际问题似乎是在您使用流导航离开视图后它会崩溃。您必须:

  • 当您离开时取消您的流控制器,使其不再监听任何事件。
  • 或者只是在导航后不通过流发出任何新值。在它上面添加一个暂停,直到你回到视图

更新:使用伪示例添加代码

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();
      }
    );
  }
}

推荐阅读