Сбой FutureBuilder(), вызывающий нулевое исключение на секунду

#flutter #dart #google-cloud-firestore #flutter-provider #flutter-futurebuilder

#флаттер #dart #google-облако-firestore #flutter-provider #flutter-futurebuilder

Вопрос:

 
class MyClass extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var _userSnapshot;
    List<dynamic> myContactsList;
    return StreamProvider<DocumentSnapshot>.value(
      value: DatabaseService("").myUser,
      builder: (context, child) => Expanded(
        child: Container(
            child: (_userSnapshot = Provider.of<DocumentSnapshot>(context)) ==
                        null ||
                    (myContactsList = _userSnapshot.data["contacts"]) == null
                ? Padding(
                    // if no contacts were found
                    padding: EdgeInsets.all(10.0),
                    child: Column(
                      children: <Widget>[
                        Text(
                          "No recent chats yet",
                        ),
                      ],
                    ),
                  )
                : ListView.builder(
                    itemCount: _userSnapshot.data["contacts"].length,
                    itemBuilder: (context, index) => FutureBuilder(
                      future: DatabaseService("").getUserById(
                        myContactsList.elementAt(index),
                      ),
                      builder: (context, snapshot) => GestureDetector(
                        onTap: () => Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (_) => ChatScreen(
                              myContactsList.elementAt(index),
                              snapshot.data["displayName"],
                            ),
                          ),
                        ),
                        child: Container(
                          margin: EdgeInsets.only(top: 5, bottom: 5, right: 20),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: <Widget>[
                              Row(
                                children: <Widget>[
                                  FutureBuilder(
                                    future: DatabaseService("").getUserById(
                                      myContactsList.elementAt(index),
                                    ),
                                    builder: (context, snapshot) =>
                                        CircleAvatar(
                                      radius: 33,
                                      backgroundImage: snapshot
                                                  .data["imageUrl"] ==
                                              null
                                          ? snapshot.data["isMale"] == true
                                              ? AssetImage(
                                                  "assets/images/male.png")
                                              : AssetImage(
                                                  "assets/images/female.png")
                                          : AssetImage(
                                              "assets/images/male.png"),
                                    ),
                                  ),
                                  SizedBox(width: 10),
                                  Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      FutureBuilder<DocumentSnapshot>(
                                        future: DatabaseService("").getUserById(
                                          myContactsList.elementAt(index),
                                        ),
                                        builder: (context, snapshot) => Text(
                                          snapshot.data["displayName"],
                                          style: TextStyle(
                                            color: Colors.grey,
                                            fontSize: 18,
                                            fontWeight: FontWeight.bold,
                                          ),
                                        ),
                                      ),
                                      SizedBox(height: 5),
                                      Container(
                                        width:
                                            MediaQuery.of(context).size.width *
                                                0.45,
                                        child: Text(
                                          "Something N. $index ",
                                          style: TextStyle(
                                            color: Colors.blueGrey,
                                            fontSize: 18,
                                            fontWeight: FontWeight.w600,
                                          ),
                                          overflow: TextOverflow.ellipsis,
                                        ),
                                      ),
                                    ],
                                  ),
                                ],
                              ),
                              Column(
                                children: <Widget>[
                                  Text(
                                    "TIME"
                                  ),
                                  Container(
                                    height: 20,
                                    width: 40,
                                    decoration: BoxDecoration(
                                      color: Theme.of(context).primaryColor,
                                      borderRadius: BorderRadius.circular(30),
                                    ),
                                    alignment: Alignment.center,
                                    child: Text(
                                      "NEW",
                                      style: TextStyle(
                                        color: Colors.white,
                                        fontSize: 11,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  ),
          ),
        ),
      ),
    );
  }
}
  

Каждый раз, когда я взаимодействую со своим приложением и запускаю изменение в моей облачной базе данных Firestore, я получаю снимок, используя StreamProvider() . И когда это происходит, я получаю некоторые исключения, перечисленные ниже, но через полсекунды экран фиксируется, вероятно, из-за нового снимка, я думаю (?).
Как указано ниже, проблема возникает из FutureBuilder() -за того, что я использую.
Вот ошибка:

 The following NoSuchMethodError was thrown building FutureBuilder<DocumentSnapshot>(dirty, state: _FutureBuilderState<DocumentSnapshot>#98dd9):
The method '[]' was called on null.
Receiver: null
Tried calling: []("imageUrl")

The relevant error-causing widget was: 
  FutureBuilder<DocumentSnapshot> file:///home/pss/Desktop/android/flutter_firebase_chat_app/lib/widgets/recent_chats.dart:90:35
When the exception was thrown, this was the stack: 
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1      RecentChats.build.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:flutter_firebase_chat_app/widgets/recent_chats.dart:98:56)
#2      _FutureBuilderState.build (package:flutter/src/widgets/async.dart:740:55)
#3      StatefulElement.build (package:flutter/src/widgets/framework.dart:4663:28)
#4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4546:15)
...
════════════════════════════════════════════════════════════════════════════════════════════════════

Another exception was thrown: NoSuchMethodError: The method '[]' was called on null.

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The method '[]' was called on null.
Receiver: null
Tried calling: []("displayName")
The relevant error-causing widget was: 
  FutureBuilder<DocumentSnapshot> file:///home/pss/Desktop/android/flutter_firebase_chat_app/lib/widgets/recent_chats.dart:114:39
  

Ошибки указывают на эти 2 строки:
backgroundImage: snapshot.data["imageUrl"] == null
amp;
builder: (context, snapshot) => Text(snapshot.data["displayName"]

Так что я не уверен, если честно. Я думаю, что это причина FutureBuilder() причины, без них я не получаю исключений. Я новичок в Flutter, поэтому буду признателен за любые советы!

Комментарии:

1. Вы пытаетесь вызвать _userSnapshot.data[], но данные равны нулю, сначала вы должны убедиться, что _userSnapshot не равен null, а _userSnapshot . данные тоже

2. я проверю, спасибо, но имейте в виду, что на экране моего телефона будут отображаться желто-черные полосы всего на полсекунды, а затем он каким-то образом правильно отображает изображения.

3. Итак, вам нужно подумать о том, чтобы поместить заполнитель, чтобы не делать его странным, CircularProgressIndicator в качестве start, вы можете использовать библиотеку Shimmer из pub.dev для загрузки некоторых интересных заполнителей (например, facebook)

4. да, я уже думал об этом. Я думаю, это необходимо для некоторых операций! Спасибо

5. так что я не утверждал моментальный снимок. данные и это устраняет проблему, я думаю.

Ответ №1:

Вы пытаетесь вызвать _userSnapshot.data[] , но data есть null , вы должны сначала убедиться, что _userSnapshot это не null и _userSnapshot.data тоже.
В то же время, подумайте о том, чтобы поместить загрузчик, который вы можете использовать CircularProgressIndicator как easy start, или вы можете использовать Shimmer библиотеку из pub.dev для какой-нибудь классной анимации загрузки заполнителя (например, Facebook).

Ответ №2:

Вы можете установить параметр initialData в StreamProvider, эти данные используются, пока поток еще ничего не выдал. Вы также должны проверить, что _userSnapshot .данные != null перед доступом к одному из его ключей.