Flutter Firebase The method 'data' was called on null

Issue

I’m using Firestore and I tried to get streams by Streambuilder.
However, This error happened.

The following NoSuchMethodError was thrown building StreamBuilder<DocumentSnapshot<Object>> 
(dirty, state: _StreamBuilderBaseState<DocumentSnapshot<Object>, 
AsyncSnapshot<DocumentSnapshot<Object>>>#32fdb):
The method 'data' was called on null.
Receiver: null
Tried calling: data()

And this is my code.

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:flutter/material.dart';
    
    class UserDetailPage extends StatefulWidget {
      String uid;
      UserDetailPage(this.uid);
    
      @override
      _UserDetailPageState createState() => _UserDetailPageState();
    }
    
    class _UserDetailPageState extends State<UserDetailPage> {
      final List<String> datas = <String>['a', 'b', 'c', 'd', 'e', 'f', 'g', '1', '2','3', '4', '5', '6'];
      CollectionReference userstream = FirebaseFirestore.instance.collection('users');
    
      @override
      void initState() {
        super.initState();
    
      }
    
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('User Detail'),
          ),
          body:_buildBody(),
        );
      }
    
     _buildBody() {
    
        return StreamBuilder(
          stream: userstream.doc(widget.uid).snapshots(),
          builder: (context, snapshot){
            Map<String, dynamic> user_data =snapshot.data.data();
            if(snapshot.hasError){
              return Text('ERROR');
            }
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Center(child: CircularProgressIndicator());
            }
    
            return Padding(
              padding: const EdgeInsets.all(20.0),
              child: ListView.separated(
                padding: EdgeInsets.only(left: 20, right: 20),
                itemCount: 13,
                separatorBuilder: (BuildContext context, int index) => const Divider(),
                itemBuilder: (BuildContext context, int index){
                  return Center(
                    child: Container(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceAround,
                        children: [
                          Text(datas[index]),
                          Text(user_data[datas[index]] is int?user_data[datas[index]].toString():user_data[datas[index]])
                        ],
                      ),
                    ),
                  );
                }
              )
            );
          },
        );
      }
    }

Interesting thing is that Immediately after this error occurs, the result I wanted appears on the app.
So I thought the problem occurs in initstate() but I dont know exactly what is wrong.

By the way, this Page is called from

UserDetailPage( doc.get('uid')!=null?doc.get('uid'):'5AJUsH5LYaQcBiTtO5MA7d6OKx72');

Solution

The AsyncSnapshot wraps data that is loaded asynchronously. Calling snapshot.data without checking whether the data is available (as you do in the code below), means you are ignoring this fact and might as well not use a StreamBuilder:

  stream: userstream.doc(widget.uid).snapshots(),
  builder: (context, snapshot){
    Map<String, dynamic> user_data =snapshot.data.data();

The proper way to deal with the stream is shown in the FlutterFire documentation on realtime listeners. The required change for you is that you only call snapshot.data after all the checks, instead of before them:

  builder: (context, snapshot){
    if(snapshot.hasError){
      return Text('ERROR');
    }
    if (snapshot.connectionState == ConnectionState.waiting) {
      return Center(child: CircularProgressIndicator());
    }
    Map<String, dynamic> user_data =snapshot.data.data();
  

Answered By – Frank van Puffelen

Answer Checked By – Candace Johnson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.