4

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”。

4

2 回答 2

2

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

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

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

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();
      }
    );
  }
}
于 2019-02-28T03:30:29.990 回答
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 更新时,它将更新较低的小部件。

现在这样,当您在较低的小部件中点击卡片进行导航时,它不应影响最高的小部件,因为它只会影响 UI。

我们将流构建器放在它自己的顶级小部件中......

我希望我有点道理:(

我没有测试就写了代码,但我确定你可以让它工作

于 2019-03-08T07:14:16.113 回答