更正 Flutter 应用中 StreamBuilder 的 Null Safety 问题

Correcting Null Safety issue with StreamBuilder in Flutter app

我的 flutter 应用程序中的 StreamBuilder 存在空安全问题。

在构建器的左括号“{”上:属性我收到此错误 正文可能会正常完成,导致 'null' 被 returned,但 return 类型可能是不可为 null 的类型。

这是 StreamBuilder 的代码。

StreamBuilder (
        stream: _db.collection('agency').doc(globals.agencyId).
        collection('trxns').doc(globals.currentTrxnId).snapshots(),
        builder: (BuildContext context, AsyncSnapshot trxnSnapshot) {
          if (trxnSnapshot.hasData) {
            var outPut = (trxnSnapshot.data() as QueryDocumentSnapshot);
            clientFNameController.text = trxnSnapshot.data.data['clientFName'] ?? "";
          }
),

我尝试添加这样的类型:StreamBuilder ( 但我收到此错误:参数类型 'Stream<DocumentSnapshot<Map<String, dynamic>>>' 无法分配给参数类型 'Stream<QuerySnapshot<Object?>>?'.

现在我更改类型以匹配上面的语句,现在我回到了原始错误消息。这是我将类型更改为。

StreamBuilder <DocumentSnapshot<Map<String, dynamic>>>(
        stream: _db.collection('agency').doc(globals.agencyId).
        collection('trxns').doc(globals.currentTrxnId).snapshots(),
        builder: (BuildContext context, AsyncSnapshot trxnSnapshot) {
          if (trxnSnapshot.hasData) {
            var outPut = (trxnSnapshot.data() as QueryDocumentSnapshot);
            clientFNameController.text = trxnSnapshot.data.data['clientFName'] ?? "";
          }
),

我不知道出了什么问题或如何解决。我知道我需要这个“!”或这个 ”?”但我不知道该放哪一个或放在哪里。

非常感谢您的帮助。

StreamBuilder 必须在其 builder 参数中 return 一个 Widget。如果你不需要显示任何 Widget(只是做一些后台更新),你可以使用 StreamSubscription 代替:

class _MyWidgetState extends State<MyWidget> {
  late final StreamSubscription<DocumentSnapshot> _subscription;
 
  @override
  void initState() {
    super.initState();
  
    final Stream<DocumentSnapshot> stream = _db
        .collection('agency')
        .doc(globals.agencyId)
        .collection('trxns')
        .doc(globals.currentTrxnId)
        .snapshots();

    _subscription = stream.listen((data) {
      if (data == null) return;
      setState(() => clientFNameController.text = data['clientFName'] ?? "");
    });
  }

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

但是,如果您想继续使用 StreamBuilder,您可以

  1. 只是 return 一个空的小部件(这不是一个好的做法):
StreamBuilder(
  stream: _db
      .collection('agency')
      .doc(globals.agencyId)
      .collection('trxns')
      .doc(globals.currentTrxnId)
      .snapshots(),
  builder: (BuildContext context, AsyncSnapshot trxnSnapshot) {
    if (trxnSnapshot.hasData) {
      var outPut = (trxnSnapshot.data as QueryDocumentSnapshot);
      clientFNameController.text = outPut.data['clientFName'] ?? "";
    }
    return SizedBox.shrink();
  },
),
  1. return一个有意义的基于每个操作的Widget:
StreamBuilder(
  stream: _db
      .collection('agency')
      .doc(globals.agencyId)
      .collection('trxns')
      .doc(globals.currentTrxnId)
      .snapshots(),
  builder: (BuildContext context, AsyncSnapshot trxnSnapshot) {
    if (trxnSnapshot.hasData) {
      var outPut = (trxnSnapshot.data as QueryDocumentSnapshot);
      clientFNameController.text = outPut.data['clientFName'] ?? "";
      return Text("client name updated");
    }
    return Text("client name not updated");
  },
),