如何在Flutter中缓存Firebase数据? [英] How to cache Firebase data in Flutter?

查看:81
本文介绍了如何在Flutter中缓存Firebase数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我使用Firebase中的数据构建对象列表。在StreamBuilder中,我检查快照是否包含数据。如果没有,我将返回一个带有正在加载...的简单文本小部件。我的问题是,如果我转到应用程序中的另一个页面,然后再返回,您会在屏幕中间看到片刻的内容为正在加载...,这有点令人讨厌。我很确定它是从Firebase下载数据,并在每次返回该页面时都构建窗口小部件。而且,如果我不检查数据,它会为我提供一个我试图从null访问数据的数据。

In my app I build a list of objects using data from Firebase. Inside a StreamBuilder, I check if the snapshot has data. If it doesen't, I am returning a simple Text widget with "Loading...". My problem is that if I go to another page in the app, and then come back, you can see for a split second that it says 'Loading...' in the middle of the screen, and it is a bit irritating. I am pretty sure it is downloading the data from Firebase, and building the widget every time I come back to that page. And if I don't do the check for data, it gives me a data that I am trying to access data from null.

是否可以缓存数据?

这里有我的代码的编辑版本:

Heres a redacted version of my code:

class Schedule extends StatefulWidget implements AppPage {
  final Color color = Colors.green;
  @override
  _ScheduleState createState() => _ScheduleState();
}

class _ScheduleState extends State<Schedule> {
  List<Event> events;
  List<Event> dayEvents;
  int currentDay;
  Widget itemBuilder(BuildContext context, int index) {
    // Some Code
  }
  @override
  Widget build(BuildContext context) {
    return Center(
      child: StreamBuilder(
        stream: Firestore.instance.collection('events').snapshots(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Text("Loading...");
          }
          events = new List(snapshot.data.documents.length);
          for (int i = 0; i < snapshot.data.documents.length; i++) {
            DocumentSnapshot doc = snapshot.data.documents.elementAt(i);

            events[i] = Event(
              name: doc["name"],
              start: DateTime(
                doc["startTime"].year,
                doc["startTime"].month,
                doc["startTime"].day,
                doc["startTime"].hour,
                doc["startTime"].minute,
              ),
              end: DateTime(
                doc["endTime"].year,
                doc["endTime"].month,
                doc["endTime"].day,
                doc["endTime"].hour,
                doc["endTime"].minute,
              ),
              buildingDoc: doc["location"],
              type: doc["type"],
            );
          }
          events.sort((a, b) => a.start.compareTo(b.start));
          dayEvents = events.where((Event e) {
            return e.start.day == currentDay;
          }).toList();
          return ListView.builder(
            itemBuilder: itemBuilder,
            itemCount: dayEvents.length,
          );
        },
      ),
    );
  }
}


推荐答案

到确保数据是来自Firestore的本地缓存还是来自网络,您可以执行以下操作:

To be sure whether the data is coming from Firestore's local cache or from the network, you can do this:

          for (int i = 0; i < snapshot.data.documents.length; i++) {
            DocumentSnapshot doc = snapshot.data.documents.elementAt(i);
            print(doc.metadata.isFromCache ? "NOT FROM NETWORK" : "FROM NETWORK");

在您描述的情况下,当其 NOT FROM NETWORK出现时,您可能仍会看到加载屏幕。这是因为从本地缓存中获取它确实需要一些时间。很快,您将可以为空的情况请求查询的元数据结果。

In the case you described you are probably going to still see the loading screen when its "NOT FROM NETWORK". This is because it does take some time to get it from the local cache. Soon you will be able to ask for the query's metadata for cases with empty results.

与其他建议一样,您可以缓存结果,但不会看到此结果。首先,您可以尝试使用以下方式将其缓存在Widget中:

Like others suggested, you can cache the results and you won't see this. First you can try to cache it in the Widget using something like:

  QuerySnapshot cache; //**

  @override
  Widget build(BuildContext context) {
    return Center(
      child: StreamBuilder(
        initialData: cache, //**
        stream: Firestore.instance.collection('events').snapshots(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Text("Loading...");
          }
          cache = snapshot.data; //**

这将使您的小部件记住数据。但是,如果不能解决问题,则必须将其保存在小部件中而不是其他位置。一种选择是使用<

This will make your widget remember the data. However, if this does not solve your problem, you would have to save it not in this widget but somewhere else. One option is to use the Provider widget to store it in a variable that lives beyond the scope of this particular widget.

code> Provider 小部件可将其存储在超出此小部件范围之外的变量中。将 Firestore.instance.collection('events')。snapshots()移至 initState(),将对流的引用保存在私有字段中,并使用它 StreamBuilder 。否则,在每个build()处,您可能正在创建一个新的流。无论出于何种原因,您都应该准备好每秒进行多次的 build()调用。

Probably not related, but it's also a good idea to move the Firestore.instance.collection('events').snapshots() to initState(), save the reference to the stream in a private field and use that it StreamBuilder. Otherwise, at every build() you may be creating a new stream. You should be ready for build() calls that happen many times per second, whatever the reason.

这篇关于如何在Flutter中缓存Firebase数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆