列表为空(颤振)

Posted

技术标签:

【中文标题】列表为空(颤振)【英文标题】:List is Empty (Flutter) 【发布时间】:2021-09-20 17:54:19 【问题描述】:

我在 Flutter 中创建一个列表并将其显示在一个列中,当我运行它时它只是空的,当我打印列表时它只是打印一个数组

I/flutter (24613): []

我正在使用此代码创建列表:-

 myFunction() 
  return StreamBuilder(
  stream:
      users.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) 
 List<UserList> usersList = [];
    snapshot.data.documents.forEach((doc) 
     User user = User.fromDocument(doc);
       UserList userList = UserList(user);
       usersList.add(userList);
    );
    return Column (children: usersList);
   
  ),
 

这是我的用户类:-

class User 

final String id;
final String username;
final String email;
final String photoUrl;


User(
  this.id,
  this.username,
  this.email,
  this.photoUrl,
);

factory User.fromDocument(DocumentSnapshot doc) 
   return User(
   id: doc.data()['id'],
   username: doc.data()['username'],
   email: doc.data()['email'],
   photoUrl: doc.data()['photoUrl'],

    );
  

  

代码没有显示错误并且列没有显示,当我打印它显示的列表长度为零时:-

I/flutter (24613): 0
 

可能是什么问题??

【问题讨论】:

这部分是从哪里来的? snapshot.data.documents 我相信它在快照数据中没有数据,所以它们不会在里面循环添加它。如果里面真的有数据,你可以打印出来 你在哪里称呼这个snapshot.data.documents. @SaiPrashanth,看来您在build 下调用FutureBuilder 的方式可能是问题所在?可以分享一下最小的build 方法实现吗? @RaguSwaminathan 我从 Future Builder 切换到 StreamBuilder 并分享了一些代码...希望对您有所帮助 我已经发布了我的答案。让我知道这是否有用。 @SaiPrashanth 【参考方案1】:

我想我们需要稍微调整一些代码以使逻辑正常工作。 :)

builder 参数应该用类型指定,否则它将是dynamic 类型。在这种情况下,为了更安全,它将是QuerySnapshot。所以,

builder: (context, snapshot) 在你的代码变成

builder: (BuildContext context, AsyncSnapshot&lt;QuerySnapshot&gt; snapshot).

接下来,无需循环遍历foreach,您可以尝试如下所示。

snapshot.data.docs.map((document)      ....    

您的代码中的snapshot.data.documents 不是获取 Firestore 文档的有效方式。请参考official doc

你需要从builder返回一个widget,你已经正确完成了。但是,您错误地将List&lt;UserList&gt; 传递给Column,这将期待List&lt;Widget&gt;

return Column (children: usersList);

在这里我可以看到你正在传递usersList,它的类型是List&lt;UserList&gt;。所以你可以用ListView或类似的其他widget替换Column,因为Column不支持scroll

所以结合所有这些点点滴滴,你会得到下面的sn-p。

return StreamBuilder(
  stream: FirebaseFirestore.instance
      .collection('users')
      .orderBy('timestamp', descending: true)
      .limit(30)
      .snapshots(),  // Just for simplicity. 
  builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) 
    //When there is no data returned from the firebase.
    if (!snapshot.hasData) 
      return Center(
        child: CircularProgressIndicator(),
      );
    
    return ListView(
      children: snapshot.data.docs.map((document) 
        return Text("Title: " + document['username']);
      ).toList(),
    );
  ,
);  

为简单起见,我返回了 Text 小部件。您可以在那里实现自己的 UI。

注意:这是基本的工作示例,您需要相应地进行微调,例如使用模型类而不是根据您的要求直接访问。

您的代码

 myFunction() 
  return StreamBuilder(
  stream:
      users.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) 
 List<UserList> usersList = [];
    snapshot.data.documents.forEach((doc) 
     User user = User.fromDocument(doc);
       UserList userList = UserList(user);
       usersList.add(userList);
    );
    return Column (children: usersList);
   
  ),
 

【讨论】:

我试过这个,它仍然不起作用,当我打印快照时,我收到消息“AsyncSnapshot(ConnectionState.active,'QuerySnapshot'实例,null,null)” 您应该打印snapshot.data 以了解Instance of 'QuerySnapshot' 中的数据。即使没有返回数据,请检查您正在访问的Firebase的集合属性以获取userList 我尝试打印 snapshot.data 并收到消息“'QuerySnapshot' 实例”。但是列表仍然没有显示..我做错了什么?? 而不是 UI。尝试使用 async/await 在单独的函数中从 firebase 获取数据,看看是否有效。你也可以参考这个教程medium.com/quick-code/… 我认为我在阅读了中等教程后解决了这个问题我认为我的 orderBy 方法有问题我删除它并且它有效,感谢您的帮助...【参考方案2】:

这是我通常使用的。试试这个!请平衡代码中的括号

    FutureBuilder(
                    future: users.orderBy('timestamp', descending: true).limit(30),
                    builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) 
                      List<User>ulist=snapshot.data;
                        return ListView.builder(
                          shrinkWrap: true,
                          padding: EdgeInsets.only(top: 25,bottom: 35),
                          itemCount: evlist==null?0:evlist.length,
                          itemBuilder: (BuildContext context, int index) 
                            String evtime=evlist[index].fromdate.substring(11,16);
                            String ontime=evlist[index].fromdate.substring(0,16);
                            return Container(
                              decoration: BoxDecoration(
                                  border: Border.all(width: 1.8,color: Colors.indigo[900]),
                                  borderRadius: BorderRadius.circular(12.0),
                                  color: Colors.grey[200]
                              ),
                              margin:
                              const EdgeInsets.symmetric(horizontal: 18.0, vertical: 4.0),
                              child: ListTile(
                                leading: Icon(Icons.notifications),
                                title: Text(ulist[index].username.toString()),
                                subtitle:Text("next data"),

                              ),
                            );
                          ,
                        );
                    

【讨论】:

具体为什么? 如果您需要完成任务,未来的建设者就在那里!我不知道严格坚持流构建器的意图是什么..!【参考方案3】:

在调用数据之前,检查所有字段:

Firestore Docs

加个print()看看哪里有问题

FutureBuilder<DocumentSnapshot>(
      future: users.doc(documentId).get(),
      builder:
          (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) 

        //This
        if (snapshot.hasError) 
          return Text("Something went wrong");
        

        print(snapshot.data);

        //This
        if (snapshot.hasData && !snapshot.data!.exists) 
          return Text("Document does not exist");
        

        print(snapshot.data);

        //This
        if (snapshot.connectionState == ConnectionState.done) 
          Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
          return Text("Full Name: $data['full_name'] $data['last_name']");
        

        return Text("loading");
      ,
    );

【讨论】:

当我打印 snapshot.data 时,它会打印消息“'QuerySnapshot'的实例”。【参考方案4】:

正如“Ashutosh patole”所说,“forEach”方法不会等待迭代完成。 我认为由于这个原因,虽然您制作了一个“usersList”, 在“usersList”中构建小部件时没有数据。

要解决此问题,您最好将“forEach”更改为“for”。

void main() async 
  List<String> data = [ 'a', 'b', 'c'];
  List<String> result = [];
  data.forEach((data) async 
    await Future.delayed(Duration(seconds: 1));
    result.add(data);
    );
  print(result);
  await Future.delayed(Duration(seconds: 3));
  print(result);
  
  print('-----------------');
  
  result = [];
  for (var item in data) 
    await Future.delayed(Duration(seconds: 1));
    result.add(item);
  
  print(result);
  await Future.delayed(Duration(seconds: 3));
  print(result);

在您的代码中,您可以进行如下更改。

List<UserList> usersList = [];
for (var doc in snapshot.data.documents) 
    User user = User.fromDocument(doc);
    UserList userList = UserList(user);
    usersList.add(userList);

【讨论】:

它不起作用它只是给出错误“未定义的名称'doc'。尝试将名称更正为已定义的名称,或定义名称。” 我更改了 'var' 添加在文档前面。 任何替代解决方案??【参考方案5】:

我不太确定您是如何处理变量范围的。 这是我的最小可重现代码,它可以让您了解如何将项目添加到列表中。

class MyPage extends StatefulWidget 
  @override
  _MyPageState createState() => _MyPageState();


class _MyPageState extends State<MyPage> 
  final List<Widget> _list = [FlutterLogo()];

  @override
  void initState() 
    super.initState();

    Timer.periodic(Duration(seconds: 1), (timer) 
      if (timer.tick >= 2) timer.cancel();
      setState(() => _list.add(FlutterLogo()));
    );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Column(children: _list),
    );
  

【讨论】:

【参考方案6】:

列在获取数据之前显示数据,因此它显示空列表。为此,在获取数据后根据您的状态管理类型(提供程序中的“notifylisteners”)使用 setstate,因此屏幕将被更新,列也会显示更新的列表。

【讨论】:

【参考方案7】:

这是因为您必须等待 json 真正解析到 dart 模型。第二件事是 forEach 方法是同步的,它不会等待异步操作完成,这就是您的列表为空的原因。

This SO question 有很多不同的方法可以让列表在 Flutter 中异步工作。

【讨论】:

我已经做了 forEach Async 但是我应该在哪里添加等待... 试试User user = await User.fromDocument(doc);,让我知道它是否有效 不,它不起作用,它会给出消息“'await'应用于'用户',这不是'未来'。”

以上是关于列表为空(颤振)的主要内容,如果未能解决你的问题,请参考以下文章

如果我的列表为空,如何显示图像?

颤振谷歌登录为空

颤振错误->必须初始化不可为空的“项目”

Flutter 项目运行时显示错误无效参数:源不得为空

如何在颤振中使用foreach方法[重复]

检查列表和数据框是不是为空