0

I have an null safety issue with my StreamBuilder in my flutter app.

On the open bracket "{" of the builder: property I am getting this error The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.

Here is the code for the 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'] ?? "";
          }
),

I tried to add a type like this: StreamBuilder ( but I get this error: The argument type 'Stream<DocumentSnapshot<Map<String, dynamic>>>' can't be assigned to the parameter type 'Stream<QuerySnapshot<Object?>>?'.

Now I change the type to match the statement above and now I am back at the original error message. Here is what I changed the type to.

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'] ?? "";
          }
),

I don't know what is wrong or how to fix it. I know I need either this "!" or this "?" but I don't know which one or where to put it.

I would really appreciate some help here.

LostTexan
  • 431
  • 5
  • 18

1 Answers1

3

A StreamBuilder must return a Widget in its builder parameter. If you don't need to show any Widget (just do some background update), you can use a StreamSubscription instead:

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

However, if you want to keep using StreamBuilder, you can

  1. just return an empty Widget (not really a good practice):
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 a meaningful Widget based on each operation:
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");
  },
),
enzo
  • 9,861
  • 3
  • 15
  • 38