【问题标题】:snapshot.data.length in the itemcount does not work: "The getter 'length' was called on null"itemcount 中的 snapshot.data.length 不起作用:“在 null 上调用了 getter 'length'”
【发布时间】:2019-06-18 03:29:09
【问题描述】:

我正在尝试使用以下代码从 firestore 获取文档:

 Future getCategories() async {
    var firestore = Firestore.instance;
    QuerySnapshot qn = await firestore.collection("categories").getDocuments();
    return qn.documents;
  }

 @override
  Widget build(BuildContext context) {
    return Container(
      child:FutureBuilder(
        future:getCategories(),
        builder:(context, snapshot){
          if(snapshot.connectionState == ConnectionState.waiting){
            return Center(
              child:Text("Loading...")
            );
         }
         else
         {
           return GridView.builder(
             itemCount: snapshot.data.length,
             gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
                 crossAxisSpacing: 6.0, mainAxisSpacing: 6.0, crossAxisCount: 2),
              itemBuilder: (BuildContext context, int index) {
                return SingleCategory(
                  category_name:  snapshot.data[index].data["title"],
                  category_picture: snapshot.data[index].data["picture"],
                );
              }
           );
         }
        }
      )
    );

当我运行代码时,我收到以下错误:

I/flutter (7555): ══╡ 小部件库发现的异常 ╞═════════════════════════════════════════════════ ══════════ I/颤振 (7555):以下 NoSuchMethodError 被抛出构建 FutureBuilder(脏,状态:I/flutter(7555): _FutureBuilderState#c3e7b):I/flutter (7555):getter 'length' 被调用为 null。 I/颤振(7555):接收器:空 I/flutter(7555):尝试调用:长度 I/flutter(7555):I/flutter (7555):抛出异常时,这是堆栈:I/flutter (7555):#0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)

谁能帮帮我。

【问题讨论】:

  • 错误信息是明确的,你的snapshot.data 是空的。如果您使用FutureBuilder,请不要等待结果。
  • 我正在使用本教程:youtube.com/watch?v=6uBjMFoyT-I。为什么 await 不能与 FutureBuilder 一起使用?顺便说一句,我删除了等待,我仍然得到同样的错误
  • @bangbang 只需打开调试器并检查snapshot 对象。注意字段snapshot.errorsnapshot.connectionState
  • 抱歉,我的意思是您不一定需要 FutureBuilder,因为您已经在 await 声明之后立即获得了结果。 var result = await getCategories(); print('done'); 应与 getCategories().then((result) { print('done'); }) 相同,FutureBuilder<Categories>( future: getCategories(), builder: (context, snapshot){ print('done'); } ); 相同。但这确实可能不是您问题的根源。
  • 这是我发现的:连接状态是 ConnectionState.waiting 快照错误是 PlatformException(执行 getDocuments 时出错,PERMISSION_DENIED:缺少权限或权限不足。,null)

标签: dart flutter google-cloud-firestore


【解决方案1】:

正如我们在 cmets 中发现的,您正在使用身份验证规则,该规则拒绝所有请求的访问:

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
       allow read, write: if false;
    }
  }
}

我想你想写这样的东西(只读模式):

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
       allow read;
       allow write: if false;
    }
  }
}

试试这个规则

【讨论】:

  • 伟大的基里尔!
  • 这就是我需要的!完美
【解决方案2】:

您应该在 FutureBuilder 小部件中添加 initialData 属性并将其设置为 [] 空列表。例如:

FutureBuilder(  // only add initialData: []
    initilData: [],  // this is vital to get rid of null length error
    future:getCategories(),
    builder:(context, snapshot){
      if(snapshot.connectionState == ConnectionState.waiting){
        return Center(
          child:Text("Loading...")
        );
     } // and same code goes below

所以,我们的主要目的是防止空长度错误,通过将 initialData 属性添加到空数组可以解决我们的问题。 这是这个属性的官方定义---

将用于创建快照的数据提供,直到 非空未来已完成。 我们也可以添加一些加载小部件来不向用户显示空白屏幕。

我们可以添加一个条件“当快照的数据等于空数组(或 data.length == 0)时,如果它显示加载小部件,否则显示列表”。 p>

【讨论】:

  • 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的答案添加解释并说明适用的限制和假设。
【解决方案3】:

最简单的方法是使用快照的hasData参数。

if (snapshot.hasData) { return GridViewBuilder(...);} 

【讨论】:

    【解决方案4】:

    试试这个:

     future: getData(),
                  builder: (context, AsyncSnapshot<List<User>> snapshot)
    

    【讨论】:

      【解决方案5】:

      我有同样的问题尝试使用这个。

       builder:(ctx, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot)
      

      如果您需要文档的长度,则包含 listView 的 itemCount 的完整 StreamBuilder 代码

      StreamBuilder(
              stream: FirebaseFirestore.instance.collection('categories').snapshots(),
              builder:
                  (ctx, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                }
                return ListView.builder(
                    itemCount: snapshot.data.docs.length,
                    itemBuilder: (ctx, index) => Text('sample'));
              });
      

      【讨论】:

        【解决方案6】:

        这是使用http集成api的完整解决方案

        1. 请添加http依赖: http: ^0.13.3

        2. 导入http包: 将“包:http/http.dart”导入为 http;

        3. 在 AndroidManifest.xml 中添加 Internet 权限。

        4. 这里是使用http从Api获取数据的完整代码。

            import 'dart:convert';
            import 'package:flutter/material.dart';
          
            void main() {
              runApp(MyApp());
            }
          
           class MyApp extends StatelessWidget {
                @override
                Widget build(BuildContext context) {
                  return MaterialApp(
                       title: 'Food recipe',
                       debugShowCheckedModeBanner: false,
                       theme: ThemeData(
                           primarySwatch: Colors.blue,
                           primaryColor: Colors.white,
                           textTheme: TextTheme(
                           bodyText2: TextStyle(color: Colors.white),
                     ),
                   ),
                 home: DataFromApi(),
              );
             }
            }
          
            class DataFromApi extends StatefulWidget {
               @override
              _DataFromApiState createState() => _DataFromApiState();
             }         
          
            class _DataFromApiState extends State<DataFromApi> {
             Future<List<Data>> getData() async {
              var response =
               await http.get(Uri.https('jsonplaceholder.typicode.com', 'users'));
               var jsonData = jsonDecode(response.body);
              List<Data> dataList = [];
              for (var u in jsonData) {
                   Data data = Data(u["name"], u["phone"], u["email"]);
                   dataList.add(data);
               }
              print(dataList.length);
              return dataList;
             }
          
             @override
             Widget build(BuildContext context) {
             return Scaffold(
             appBar: AppBar(
                  title: Text("Data Fetch"),
              ),
             body: Container(
                 child: Card(
                   child: FutureBuilder<List<Data>>(
                  future: getData(),
                  builder: (context, snapshot) {
                      if (snapshot.data == null) {
                       return Container(
                      child: Text("Loading"),
                      );
                   }else{
                      return ListView.builder(
                            itemCount: snapshot.data!.length,
                            itemBuilder: (context, i) {
                              return ListTile(
                                  title: Column(
                                  children: [
                                        Text(snapshot.data![i].name),
                                        Text(snapshot.data![i].phone),
                                        Text(snapshot.data![i].email),
                                  ],
                                ),
                              );
                           });
                       }
                    },
                 ),
                ),
              ));
           }
          }
          
          class Data {
            final String name, phone, email;
          
            Data(this.name, this.phone, this.email);
          }
          

        【讨论】:

          【解决方案7】:

          您可以使用动态

               child: FutureBuilder<dynamic>(
                    future: getApiData(),
                     ...
                     ...
          

          它对我有用。

          【讨论】:

            猜你喜欢
            • 2021-07-21
            • 2021-08-11
            • 2021-02-23
            • 2021-12-10
            • 2018-12-03
            • 2020-06-15
            • 2021-05-25
            • 2023-03-08
            相关资源
            最近更新 更多