firebase - Flutter:从 Firestore 延迟加载数据

标签 firebase asynchronous flutter dart google-cloud-firestore

注意:我已经看到了关于 ListView 延迟加载的答案,但这些是针对自定义 API 而不是 Firestore 数据库的!

我有一个书籍摘要应用程序,该应用程序从我的 Firebase/Firestore 中获取数据数据库,然后使用 ListView.builder 显示它包裹在 StreamBuilder 中.

现在,我想懒惰地获取数据,我的意思是当用户滚动列表时,加载所需的数据,而不是一次加载数据然后懒惰地显示它。

//The Widget used to display data:

Widget feed() {
  return Container(
    width: deviceWidth,
    height: deviceHeight / 3,
    child: StreamBuilder(
        stream: Firestore.instance
            .collection('feedItem')
            .orderBy('feedId', descending: true)
            .snapshots(),

        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.hasData) {
            int totalLength = snapshot.data.documents.length;
            return ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: totalLength > 10 ? 10 : totalLength,
              itemBuilder: (BuildContext context, int index) {
                return Container(
                  width: deviceWidth / 2.5,
                  child: GestureDetector(
                    onTap: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (BuildContext context) => FeedIntro(
                                  snapshot.data.documents[
                                      ((totalLength - 1) - index)]['feedId'])));
                    },
                    child: Card(
                        child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: <Widget>[
                        Container(
                          // width: 150,
                          height: 150,
                          foregroundDecoration: BoxDecoration(
                              image: DecorationImage(
                                  image: NetworkImage(
                                    snapshot.data.documents[index]['feedImage'],
                                  ),
                                  fit: BoxFit.fill)),
                        ),
                        Center(
                            child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Text(snapshot.data.documents[index]['title']),
                        )),
                      ],
                    )),
                  ),
                );
              },
            );
          } else if (snapshot.hasError) {
            return Center(child: Text('Sorry Something went wrong!'));
          } else {
            return Center(
              child: SizedBox(
                child: CircularProgressIndicator(),
                width: 50,
                height: 50,
              ),
            );
          }
        }),
  );
}

最佳答案

延迟加载的描述似乎与分页匹配。这是在 ListView.builder 中使用带分页的 Firestore 的简单演示
此示例实现了来自 Firebase 官方文档 Firestore pagination 的片段.
在这个演示中有两种方法可以在 View 上加载数据。

  • 刷新整个ListView使用
    RefreshIndicator
  • 向下滚动到列表底部以加载 ListView 中的下一个文档。 .
    ScrollController
    用于确定用户是否点击了列表的底部。

  • import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:flutter/material.dart';
    
    import 'DocObj.dart';
    
    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
      // Initialize Firebase
      await Firebase.initializeApp();
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var scrollController = ScrollController();
    
      @override
      void initState() {
        super.initState();
        getDocuments();
        scrollController.addListener(() {
          if (scrollController.position.atEdge) {
            if (scrollController.position.pixels == 0)
              print('ListView scroll at top');
            else {
              print('ListView scroll at bottom');
              getDocumentsNext(); // Load next documents
            }
          }
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: listDocument.length != 0
                ? RefreshIndicator(
                    child: ListView.builder(
                      physics: AlwaysScrollableScrollPhysics(),
                      controller: scrollController,
                      itemCount: listDocument.length,
                      itemBuilder: (context, index) {
                        return ListTile(
                          title: Text('${listDocument[index].documentName}'),
                        );
                      },
                    ),
                    onRefresh: getDocuments, // Refresh entire list
                  )
                : CircularProgressIndicator(),
          ),
        );
      }
    
      List<DocObj> listDocument;
      QuerySnapshot collectionState;
      // Fetch first 15 documents
      Future<void> getDocuments() async {
        listDocument = List();
        var collection = FirebaseFirestore.instance
            .collection('sample_pagination')
            .orderBy("name")
            .limit(15);
        print('getDocuments');
        fetchDocuments(collection);
      }
    
      // Fetch next 5 documents starting from the last document fetched earlier
      Future<void> getDocumentsNext() async {
        // Get the last visible document
        var lastVisible = collectionState.docs[collectionState.docs.length-1];
        print('listDocument legnth: ${collectionState.size} last: $lastVisible');
    
        var collection = FirebaseFirestore.instance
            .collection('sample_pagination')
            .orderBy("name").startAfterDocument(lastVisible).limit(5);
    
        fetchDocuments(collection);
      }
    
      fetchDocuments(Query collection){
        collection.get().then((value) {
          collectionState = value; // store collection state to set where to start next
          value.docs.forEach((element) {
            print('getDocuments ${element.data()}');
            setState(() {
              listDocument.add(DocObj(DocObj.setDocDetails(element.data())));
            });
          });
        });
      }
    }
    
    要解析文档中的数据,您可以为您的对象创建一个模型。
    class DocObj {
      var documentName;
    
      DocObj(DocObj doc) {
        this.documentName = doc.getDocName();
      }
    
      dynamic getDocName() => documentName;
    
      DocObj.setDocDetails(Map<dynamic, dynamic> doc)
          : documentName = doc['name'];
    }
    
    该示例处理来自 Firestore 的这些数据。
    firestore dashboard
    这是应用程序在运行时的外观。
    demo

    关于firebase - Flutter:从 Firestore 延迟加载数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56411802/

    相关文章:

    java - 如何在具有多个 Firebase 项目的一个应用程序中设置 Firebase crashltycs

    c# - 在捕获 block 中等待

    image - 是否可以使用 Dart/Flutter 绘制图像?

    java - 从 java.util.concurrent.Future<T> 到 play.libs.F.Promise<T> : How to do that in Java?

    ios - 无效的 `Podfile` 文件 : No such file or directory @ rb_sysopen - flutter_module⁩/. ios/Flutter/podhelper.rb

    flutter - 任务 ':app:processDebugResources' 执行失败

    javascript - 谷歌云/firebase 存储错误 : Cannot sign data without `client_email` . ...名称: 'SigningError'

    reactjs - 在 jspm 中安装 ReactFire 时出现 EPERM 错误

    android - DialogFragment getActivity() 在 fragment 处理其他数据后返回 null

    javascript - JavaScript WebSocket.send 方法会阻塞吗?