flutter itemcount中的snapshot.data.length不起作用:“getter 'length'在null上被呼叫”

11dmarpk  于 2022-12-05  发布在  Flutter
关注(0)|答案(7)|浏览(104)

我正在尝试从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/扑动(7555):由小工具库捕获的异常(7555):在构建FutureBuilder(脏,状态:I/扑动(7555):_未来生成器状态#c3e7b):I/扑动(7555):在null. I/flutter(7555)上调用了getter“length”:接收器:零I/ Flutter (7555):已尝试呼叫:长度I/扑动(7555):I/扑动(7555):抛出异常时,堆栈如下:I/扑动(7555):第0个对象。noSuchMethod(dart:核心/运行时/libobject_patch.dart:50:5)
有人能帮我吗?

nfs0ujit

nfs0ujit1#

试试这个:

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

pjngdqdw2#

这是使用http的api集成的完整解决方案。
1.请添加http依赖项:文件
1.导入http包:将“package:http/http.dart”导入为http;
1.在AndroidManifest.xml中添加Internet权限。
1.下面是使用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);
}
b1uwtaje

b1uwtaje3#

正如我们在评论中所发现的,您使用的是一个auth规则,它拒绝所有请求的访问:

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;
    }
  }
}

试试这个规则

but5z9lq

but5z9lq4#

您应该在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)的数据时,如果是,则显示加载小部件,否则显示列表”。*
ncecgwcz

ncecgwcz5#

我试着用这个也遇到了同样的问题。

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'));
        });
xytpbqjk

xytpbqjk6#

您可以使用动态

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

对我很有效。

0h4hbjxa

0h4hbjxa7#

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

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

相关问题