繁体   English   中英

Flutter & Firebase:FutureBilder 出错

[英]Flutter & Firebase: Error with FutureBilder

目前,我正在开发一款餐饮和购物应用程序。 在此应用程序中,您可以添加接下来想吃的东西,并有第二个选项卡“购物”,您可以在其中添加接下来要购买的物品。 创建是一个用户可以邀请另一个用户一起编辑列表。

我收到如下所示的错误。 我不知道如何返回容器。 在 void saveInviteToFirestore 中,用户未被使用,我需要它被使用吗?

代码

import 'package:flutter/material.dart';
import 'package:mealapp/models/Widgets/whenAndWhatToEat.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
import 'package:mealapp/models/global.dart';
import 'package:status_alert/status_alert.dart';
import 'package:firebase_auth/firebase_auth.dart';

class MealTile extends StatefulWidget {
  final MealsAndWhen mealsAndWhen;
  MealTile({this.mealsAndWhen});

  @override
  MealTileState createState() {
    return MealTileState();
  }
}

class MealTileState extends State<MealTile> {
  String id;
  final db = Firestore.instance;
  String mail;
  List<String> authors = [];

  DateTime selectedDate = DateTime.now();

  Future pickDate() async {
    DateTime datepick = await showDatePicker(
        context: context,
        initialDate: new DateTime.now(),
        firstDate: new DateTime.now().add(Duration(days: -0)),
        lastDate: new DateTime.now().add(Duration(days: 365)));
    if (datepick != null)
      setState(() {
        selectedDate = datepick;
      });
  }

  Future<String> inputData() async {
    final FirebaseUser user = await FirebaseAuth.instance.currentUser();
    return user != null ? user.uid : null;
  }

  Future<String> inputDataMail() async {
    final FirebaseUser user = await FirebaseAuth.instance.currentUser();
    return user != null ? user.email : null;
  }

  String userId;

  void _getUserId() {
    inputData().then((value) => setState(() {
          userId = value;
        }));
  }

  String currentMail;

  void _getMail(doc) {
    inputDataMail().then((value) => setState(() {
          currentMail = value;
        }));
  }

  /*void _getAuthors(DocumentSnapshot doc) async {
    authors = [];
    //if (await FirebaseAuth.instance.currentUser() != null) {
      authors = List.from(doc.data['Authors']);
      print(doc.data['authors']);
      //authors.insert(0, currentMail);
    //}
  }*/

  Widget buildItem(DocumentSnapshot doc) {
    DateTime now = doc.data['Date'].toDate();
    DateFormat formatter = DateFormat('dd-MM-yyyy');
    String formatted = formatter.format(now);
    _getUserId();
    _getMail(doc);
    if (doc.data['Authors'] != null) {
      //_getAuthors(doc);
      //print('Current mail: ' + currentMail + authors.toString() + doc.data['Author'] + doc.data['Meal']);
    }

    if (now.day == DateTime.now().day) { // If the Date of the meal is today
      deleteData(doc, false); // Delete it!
    }
    // You could also change ".day" to ".hour".
    // Example: if (now.day == DateTime.now().day && now.hour == DateTime.hour())
    // So, if a meal is set for 2PM, it will delete at 2PM

    return FutureBuilder<FirebaseUser>(
        future: FirebaseAuth.instance.currentUser(),
        builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
          if (snapshot.hasData && snapshot != null) {
            return Container(
              margin: const EdgeInsets.all(8.0),
              child: currentMail == doc.data['Author'] || // If the current mail is the author
                      List.from(doc.data['Authors']).contains(currentMail) // Or if the current mail is part of the authors
                  ? Column( // then if  true, show a Column
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: <Widget>[
                        Text(
                          'Meal:',
                          style: TextStyle(
                              fontSize: 24,
                              fontWeight: FontWeight.bold,
                              color: Colors.white),
                          textAlign: TextAlign.center,
                        ),
                        Text(
                          '${doc.data['Meal']}',
                          style: TextStyle(
                              fontSize: 24,
                              fontWeight: FontWeight.bold,
                              color: Colors.white),
                          textAlign: TextAlign.center,
                        ),
                        SizedBox(height: 20),
                        Text(
                          'When:',
                          style: TextStyle(
                              fontSize: 20,
                              fontWeight: FontWeight.bold,
                              color: Colors.white),
                          textAlign: TextAlign.center,
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            IconButton(
                              onPressed: () => updateData(doc),
                              color: lightBlueColor,
                              icon: Icon(Icons.calendar_today,
                                  color: Colors.white),
                              tooltip: 'Update Date',
                            ),
                            Text(
                              formatted,
                              style: TextStyle(
                                  fontSize: 20,
                                  fontWeight: FontWeight.bold,
                                  color: Colors.white),
                              textAlign: TextAlign.center,
                            ),
                          ],
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.end,
                          children: <Widget>[
                            SizedBox(width: 8),
                            FlatButton(
                              color: Colors.red,
                              onPressed: () => deleteData(doc, true),
                              shape: RoundedRectangleBorder(
                                  borderRadius:
                                      BorderRadiusDirectional.circular(12)),
                              child: Row(children: <Widget>[
                                Text('Delete',
                                    style: TextStyle(
                                        fontWeight: FontWeight.bold,
                                        color: Colors.white)),
                                Icon(Icons.delete_forever, color: Colors.white),
                              ]),
                            ),
                            SizedBox(width: 8),
                            FlatButton(
                              color: Colors.blue,
                              onPressed: () => [
                                showDialog(
                                    context: context,
                                    builder: (BuildContext context) {
                                      return Dialog(
                                        child: invite(doc),
                                        shape: RoundedRectangleBorder(
                                          borderRadius: BorderRadius.all(
                                              Radius.circular(12)),
                                        ),
                                      );
                                    })
                              ],
                              shape: RoundedRectangleBorder(
                                  borderRadius:
                                      BorderRadiusDirectional.circular(12)),
                              child: Row(children: <Widget>[
                                Text('Invite',
                                    style: TextStyle(
                                        fontWeight: FontWeight.bold,
                                        color: Colors.white)),
                                Icon(Icons.share, color: Colors.white),
                              ]),
                            ),
                          ],
                        ),
                      ],
                    )
                  : Text(''), // if false, show an empty text widget
              decoration: BoxDecoration(
                color: lightBlueColor,
                borderRadius: BorderRadius.all(Radius.circular(12)),
              ),
            );
          }
          /*Navigator.pop(context);
          return HomePage();*/
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: darkGreyColor,
      body: ListView(
        padding: EdgeInsets.only(top: 220),
        children: <Widget>[
          StreamBuilder<QuerySnapshot>(
            stream: db
                .collection('mealList')
                .orderBy('Date', descending: false) // Order by Date, not descending
                .snapshots(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Column(
                    children: snapshot.data.documents
                        .map((doc) => buildItem(doc))
                        .toList());
              } else {
                return Container();
              }
            },
          ),
        ],
      ),
    );
  }

  /*share(BuildContext context, DocumentSnapshot doc) {
    final RenderBox box = context.findRenderObject();
    final dynamic date = timeago.format(doc['Date'].toDate());

    Share.share(
      "${doc['Meal']} - $date",
      subject: doc['Meal'],
      sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size,
    );
  }*/

  Widget invite(DocumentSnapshot doc) {
    final _formKey = GlobalKey<FormState>();
    return Form(
      key: _formKey,
      child: Padding(
        padding: const EdgeInsets.all(24.0),
        child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
          Center(
              child: Text(
            "Invite someone by mail",
            style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
          )),
          SizedBox(
            height: 24,
          ),
          TextFormField(
            decoration: InputDecoration(
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(12))),
                labelText: 'Enter the email address'),
            validator: (value) {
              if (value.isEmpty) {
                return 'Please enter an email address';
              }
              return null;
            },
            onSaved: (value) => mail = value,
          ),
          FlatButton(
            onPressed: () async {
              if (_formKey.currentState.validate()) {
                _formKey.currentState.save();
                saveInviteToFirestore(doc, mail);
              }
            },
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(12))),
            child: Text("Save"),
            color: redColor,
            textColor: Colors.white,
          ),
        ]),
      ),
    );
  }

  Future<String> getCurrentUser() async {
    return await FirebaseAuth.instance.currentUser().then((value) => value.uid);
  }

  void saveInviteToFirestore(DocumentSnapshot doc, String email) async {
    final String user = await getCurrentUser();
    var list = List<String>();
    list.add(email);

    Firestore.instance
        .collection('mealList')
        .document(doc.documentID)
        .updateData({"Authors": FieldValue.arrayUnion(list)});
    //setState(() => id = doc.documentID);
    StatusAlert.show(
      context,
      duration: Duration(seconds: 2),
      title: 'Added',
      subtitle: 'You have Added your and the Date to your List',
      configuration: IconConfiguration(icon: Icons.done),
    );
    //Navigator.pop(context);
  }

  void deleteData(DocumentSnapshot doc, bool showMessage) async {
    await db.collection('mealList').document(doc.documentID).delete();
    setState(() => id = null);
    if (showMessage) {
      StatusAlert.show(
        context,
        duration: Duration(seconds: 2),
        title: 'Deleted',
        subtitle: 'You have Deleted your Meal',
        configuration: IconConfiguration(icon: Icons.delete),
      );
    }
  }

  void updateData(DocumentSnapshot doc) async {
    await pickDate();
    await db
        .collection('mealList')
        .document(doc.documentID)
        .updateData({'Date': selectedDate});
    StatusAlert.show(
      context,
      duration: Duration(seconds: 2),
      title: 'Updated',
      subtitle: 'You have updated your Meal Date',
      configuration: IconConfiguration(icon: Icons.done),
    );
  }
}


错误

The following assertion was thrown building FutureBuilder<FirebaseUser>(dirty, state: _FutureBuilderState<FirebaseUser>#a4504):
A build function returned null.

The offending widget is: FutureBuilder<FirebaseUser>
Build functions must never return null.

To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "Container(width: 0.0, height: 0.0)".

The relevant error-causing widget was
    FutureBuilder<FirebaseUser> 
lib/…/MealPlan/mealTile.dart:92
When the exception was thrown, this was the stack
#0      debugWidgetBuilderValue.<anonymous closure> 
package:flutter/…/widgets/debug.dart:276

FutureBuilder中,当Future尚未完成时,您不会返回任何内容。 无论是否有数据,始终需要返回一个小部件。

您的代码的示例修复:

return FutureBuilder<FirebaseUser>(
        future: FirebaseAuth.instance.currentUser(),
        builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
          if (snapshot.hasData && snapshot != null) {
            return Container(
             ...
            );
          }
          //ADDED ELSE BLOCK
          else {
            return Container();
          }
        }
      );

或者按照@stacker 的建议,您可以返回CircularProgressIndicator()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM