具有 initialData 和 null-awareness 的 Flutter StreamBuilder

Flutter StreamBuilder with initialData and null-awareness

我在理解使用新的 null 感知运算符的 StreamBuilder 时遇到了一些问题。

作为一个学习项目,我正在使用 BloC 模式实施登录流程。对于我的电子邮件登录表单,我创建了一个模型 class,我通过 StreamBuilder 访问它。如果不使用 initialData,snapshot.data 可以为空是完全合理的。但是,将 initialData 设置为预定义的空模型,snapshot.data 永远不会为空,对吧?这是我的代码片段:

 @override
  Widget build(BuildContext context) {
    return StreamBuilder<EmailSignInModel>(
        stream: widget.bloc.modelStream,
        initialData: EmailSignInModel(),
        builder: (context, snapshot) {
          final EmailSignInModel model = snapshot.data;
          return Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisSize: MainAxisSize.min,
              children: _buildChildren(),
            ),
          );
        });
  }

编译器警告我 snapshot.data 的类型 不等于 。我可以用 snapshot.data ?? EmailSignModel() 解决这个问题,但是这对 initialData 来说是多余的吗?

处理这种情况和处理 Dart 的 null-awareness 的正确方法是什么?

深入研究源代码,我发现了以下内容:

https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/async.dart

  /// The latest data received by the asynchronous computation.
  ///
  /// If this is non-null, [hasData] will be true.
  ///
  /// If [error] is not null, this will be null. See [hasError].
  ///
  /// If the asynchronous computation has never returned a value, this may be
  /// set to an initial data value specified by the relevant widget. See
  /// [FutureBuilder.initialData] and [StreamBuilder.initialData].
  final T? data;

  /// Returns latest data received, failing if there is no data.
  ///
  /// Throws [error], if [hasError]. Throws [StateError], if neither [hasData]
  /// nor [hasError].
  T get requireData {
    if (hasData)
      return data!;
    if (hasError)
      throw error!;
    throw StateError('Snapshot has neither data nor error');
  }

AsyncSnapshot实际上有一个requireDatagetter,这将确保非空或将抛出错误。所以只需将 snapshot.data 替换为 snapshot.requireData

这仍然需要一些手动工作,其中 initialDatarequireData 的使用需要保持同步。你也可以只使用 snapshot.data! ,它基本上做同样的事情。