7

StreamBuilder 总是被调用两次吗?一次用于初始数据,然后一次用于输入流?

初始化下面的 StreamBuilder 表明 build 方法被调用了两次。第二次呼叫是在第一次呼叫之后 0.4 秒。

流:构建 1566239814897

流:构建 1566239815284

import 'dart:async';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:nocd/utils/bloc_provider.dart';

void main() =>
    runApp(BlocProvider<MyAppBloc>(bloc: MyAppBloc(), child: MyApp()));

class MyAppBloc extends BlocBase {
  String _page = window.defaultRouteName ?? "";

  /// Stream for [getPage].
  StreamController<String> pageController = StreamController<String>();

  /// Observable navigation route value.
  Stream get getPage => pageController.stream;

  MyAppBloc() {}

  @override
  void dispose() {
    pageController.close();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final MyAppBloc myAppBloc = BlocProvider.of<MyAppBloc>(context);
    return StreamBuilder(
      stream: myAppBloc.getPage,
      initialData: "Build",
      builder: (context, snapshot) {
        print("Stream: " +
            snapshot.data +
            DateTime.now().millisecondsSinceEpoch.toString());
        return Container();
      },
    );
  }
}

为什么 StreamBuilder 被调用两次?

4

3 回答 3

10

Streambuilder 将被调用 2 次,第一次用于 Initial,第二次用于流。并且数据仅在状态为ConnectionState.active 时更改。 kinldy 请参阅官方文档示例。

    StreamBuilder<int>(
  //stream:fire, // a Stream<int> or null
  builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
    if (snapshot.hasError) return Text('Error: ${snapshot.error}');
    switch (snapshot.connectionState) {
      case ConnectionState.none:
        return Text('Select lot');
      case ConnectionState.waiting:
        return Text('Awaiting bids...');
      case ConnectionState.active:
        return Text('\$${snapshot.data}');
      case ConnectionState.done:
        return Text('\$${snapshot.data} (closed)');
    }
    return null; // unreachable
  },
);

StreamBuilder 文档

可以通过指定 initialData 来控制初始快照数据。这应该用于确保第一帧具有预期值,因为总是会在流侦听器有机会处理之前调用构建器。

初始数据

提供这个值(大概是在创建 Stream 时以某种方式同步获得的)确保第一帧将显示有用的数据。否则,将使用 null 值构建第一帧,而不管流上是否有可用值:由于流是异步的,因此在初始构建之前无法从流中获取任何事件。

于 2019-12-28T11:57:50.050 回答
5

StreamBuilder 在初始化时会进行两次构建调用,一次用于初始数据,第二次用于流数据。

流不保证它们会立即发送数据,因此需要初始数据值。传递nullinitialData会引发 InvalidArgument 异常。

即使传递的流为空,StreamBuilders 也将始终构建两次。

更新:

即使提供了 StreamBuilders 也会多次构建的详细技术解释initalData可以在这个 Flutter 问题线程中找到:https ://github.com/flutter/flutter/issues/16465

广播流不可能具有初始状态。您在添加数据时订阅了或您错过了它。在异步单订阅流中,在下一个微任务或下一个事件循环(不记得,可能取决于)之前,不会调用添加的任何监听调用,但无论如何都无法将数据从在当前帧上流。- 乔纳威廉姆斯

于 2019-08-19T18:49:56.113 回答
2

如上所述,您只需将代码放入 Connection.Active 状态。见下文:

StreamBuilder<QuerySnapshot>(
              stream: historicModel.query.snapshots(),
              builder: (context, stream){

                if (stream.connectionState == ConnectionState.waiting) {
                  return Center(child: CircularProgressIndicator());
                } else if (stream.hasError) {
                  return Center(child: Text(stream.error.toString()));
                } else if(stream.connectionState == ConnectionState.active){
                   //place your code here. It will prevent double data call.

                }
于 2021-01-14T22:05:49.407 回答