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

查看:28
本文介绍了如何在 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.

有没有办法缓存已经下载的数据,如果来自 Firebase 的数据没有变化,那么就使用缓存的数据?

Is there a way to cache the data that was already downloaded, and if there has been no change in the data from Firebase, then just use the cached data?

这是我的代码的编辑版本:

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");

在您描述的情况下,您可能仍会看到加载屏幕,因为它不是来自网络".这是因为从本地缓存中获取它确实需要一些时间.很快,您将能够请求 查询的元数据结果.

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; //**

这将使您的小部件记住数据.但是,如果这不能解决您的问题,您就不必将其保存在此小部件中,而是将其保存在其他地方.一种选择是使用 Provider 小部件将其存储在超出此特定小部件范围的变量中.

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.

可能不相关,但将 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天全站免登陆