Search code examples
androidflutterfirebasegoogle-cloud-firestorestream-builder

Going through a class in my flutter course but unable to run this following code


Im trying to get items from firestore to be shown in Listview on the app but getting "build function returned null.The offending widget is: StreamBuilder,Build functions must never return null". I just want the list 'post' from firstore shown in listview.

a build function returned null. the offending widget is StreamBuilder<QuerySnapshot> Build function must never return null.

Please help me out on the issue with app


import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class ChatScreen extends StatefulWidget {
  static const String id = 'chat_screen';

  @override
  _ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  final _fireStore = FirebaseFirestore.instance;
  final _auth = FirebaseAuth.instance;
  User loggedInUser;
  String messageText;

  @override
  void initState() {

    super.initState();
    getCurrentUser();
  }

  void getCurrentUser() async {
    try {
      final user = await _auth.currentUser;
      if (user != null) {
        loggedInUser = user;
        print(loggedInUser.email);
      }
    } catch (e) {
      print(e);
    }
  }



  void messageStream() async {
    await for (var snapShot in _fireStore.collection('messages').snapshots()) {
      for (var message in snapShot.docs) {
        print(message.data());
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: null,
        actions: <Widget>[
          IconButton(
              icon: Icon(Icons.close),
              onPressed: () {
                messageStream();
                // _auth.signOut();
                // Navigator.pop(context);
              }),
        ],
        title: Text('⚡️Chat'),
        backgroundColor: Colors.lightBlueAccent,
      ),
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            StreamBuilder<QuerySnapshot>(
                stream: _fireStore.collection('messages').snapshots(),
                builder: (context, snapshot){
                  if(snapshot.hasData){
                    final messages = snapshot.data.docs;
                    List<Text> messageWidgets = [];
                    for (var message in messages){
                      final messageText = (message.data as Map<String, dynamic>)['text'];
                      final messageSender = (message.data as Map<String, dynamic>)['sender'];
                      final messageWidget = Text('$messageText from $messageSender');
                      messageWidgets.add(messageWidget);
                    } return Column(
                      children: messageWidgets,
                    );
                  }
                },),
            Container(
              decoration: kMessageContainerDecoration,
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  Expanded(
                    child: TextField(
                      onChanged: (value) {
                        messageText = value;
                      },
                      decoration: kMessageTextFieldDecoration,
                    ),
                  ),
                  FlatButton(
                    onPressed: () {
                      _fireStore.collection('messages').add({
                        'text': messageText,
                        'sender': loggedInUser.email
                      });
                    },
                    child: Text(
                      'Send',
                      style: kSendButtonTextStyle,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}




Solution

  • So the problem as you describe it is that StreamBuilder returns null even though a Widget is expected. Let's focus on that part of your code then. I cleaned up the formatting to make it easier to understand.

    StreamBuilder<QuerySnapshot>(
      stream: _fireStore.collection('messages').
      builder: (context, snapshot){
        if(snapshot.hasData) {
          final messages = snapshot.data.docs;
          List<Text> messageWidgets = [];
          for (var message in messages){
            final messageText = (message.data as Map<String, dynamic>)['text'];
            final messageSender = (message.data as Map<String, dynamic>)['sender'];
            final messageWidget = Text('$messageText from $messageSender');
            messageWidgets.add(messageWidget);
          }
          return Column(
            children: messageWidgets,
          );
        }
      },
    ),
    

    The builder function is what shall return a Widget. However, your code starts right off with an if statement and the code below will only be executed when snapshot.hasData is true. Therefore, the Column is only returned in that case.

    When the snapshot has not yet finished, i.e. has no data, or threw an error there is no else/fallback section, the code will simply return without giving a Widget back to the caller, returning null.
    This can be solved by providing fallback returns in these cases:

    StreamBuilder<QuerySnapshot>(
      ...
      builder: (context, snashot) {
        if (snapshot.hasData) {
          ...
          return Column(...);
        }
        if (snapshot.hasError) {
          return Container(
            child: Text("An error occured..."),
           );
        }
        return Container(
          child: Text("No data received yet...Loading..."),
        );
      }
    );