Cloud Firestore 不断重新下载文档 - Flutter

Bro*_*ure 2 firebase flutter google-cloud-firestore

这发生在我的主应用程序中,我使用给定的代码实验室复制它: https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html ?index=..%2F..index#10

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Baby Names',
     home: MyHomePage(),
   );
 }
}

class MyHomePage extends StatefulWidget {
 @override
 _MyHomePageState createState() {
   return _MyHomePageState();
 }
}

class _MyHomePageState extends State<MyHomePage> {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(title: Text('Baby Name Votes')),
     body: _buildBody(context),
   );
 }

Widget _buildBody(BuildContext context) {
 return StreamBuilder<QuerySnapshot>(
   stream: Firestore.instance.collection('baby').snapshots(),
   builder: (context, snapshot) {
     if (!snapshot.hasData) return LinearProgressIndicator();

     return _buildList(context, snapshot.data.documents);
   },
 );
}

Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot){
   return ListView(
     padding: const EdgeInsets.only(top: 20.0),
     children: snapshot.map((data) => _buildListItem(context, data)).toList(),
   );
 }

 Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
  final record = Record.fromSnapshot(data);

   return Padding(
     key: ValueKey(record.name),
     padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
     child: Container(
       decoration: BoxDecoration(
         border: Border.all(color: Colors.grey),
         borderRadius: BorderRadius.circular(5.0),
       ),
       child: ListTile(
         title: Text(record.name),
         trailing: Text(record.votes.toString()),
         onTap: () => print(record),
       ),
     ),
   );
 }
}

class Record {
 final String name;
 final int votes;
 final DocumentReference reference;

 Record.fromMap(Map<String, dynamic> map, {this.reference})
     : assert(map['name'] != null),
       assert(map['votes'] != null),
       name = map['name'],
       votes = map['votes'];

 Record.fromSnapshot(DocumentSnapshot snapshot)
     : this.fromMap(snapshot.data, reference: snapshot.reference);

 @override
 String toString() => "Record<$name:$votes>";
}
Run Code Online (Sandbox Code Playgroud)

我唯一使用的插件是cloud_firestore 0.9.5+2。请您对这个测试过程保持耐心。您不会立即看到该问题。首先运行应用程序,设置该项目。您可以按照给定 Codelab 中的说明进行操作。一旦前端和后端的一切都设置完毕(在firstore上创建文档)。去吃午饭、吃晚饭、玩电子游戏或和朋友出去玩。1小时后回来。运行该应用程序,您将需要为那些新读取的内容产生费用。再做一次,1小时后回来,同样的事情还会发生

如何在现实生活中复制它:通过 Codelab 中的给定代码启动此应用程序。运行它,如果您将 4 个文档存储到 firestore 中,它应该会产生 4 个文档读取。

再次启动。不收取任何阅读费用。太棒了,它有效!但不,事实并非如此。

第二天我醒来,打开应用程序,我读了 4 次。好吧,也许发生了一些魔法。我立即重新启动它,并且没有产生任何费用(太棒了!)。1 小时后,我启动应用程序,并被收取 4 次读取费用,以显示完全没有更改的 4 个相同文档。

问题是,在应用程序启动时。它似乎正在从查询快照下载文档。文件没有发生任何变化。该流构建器之前已运行过多次。

离线模式(飞行模式),缓存数据显示没有问题。

例如,在我的主应用程序中,我有一个 photoUrl,在新的应用程序启动时,您可以看到它从 firestore 加载(意味着作为新文档下载,从而产生读取费用)。我重新启动我的主应用程序,不收取任何费用,并且照片不刷新(太棒了!)。1 小时后,我启动应用程序,并对我检索的每个文档进行收费(没有更改)。

这是 cloud firestore 应该表现的方式吗? 根据我所读到的内容,它不应该像这样:(

Gün*_*uer 5

build()除了构建小部件树之外,您不应该做实际的工作

而不是在构建中这样的代码

stream: Firestore.instance.collection('baby').snapshots(),
Run Code Online (Sandbox Code Playgroud)

你应该使用

Stream<Snapshot> babyStream;
@override
void initState() {
  super.initState();
  babyStream = Firestore.instance.collection('baby').snapshots();
}

Widget _buildBody(BuildContext context) {
 return StreamBuilder<QuerySnapshot>(
   stream: babyStream,
   builder: (context, snapshot) {
     if (!snapshot.hasData) return LinearProgressIndicator();

     return _buildList(context, snapshot.data.documents);
   },
 );
}
Run Code Online (Sandbox Code Playgroud)

FutureBuilder 文档没有明确提到它,但它是一样的

https://docs.flutter.io/flutter/widgets/FutureBuilder-class.html

未来必须更早获得,例如在 State.initState、State.didUpdateConfig 或 State.didChangeDependencies 期间。在构造 FutureBuilder 时,它不能在 State.build 或 StatelessWidget.build 方法调用期间创建。如果future和FutureBuilder同时创建,那么每次重建FutureBuilder的parent时,异步任务都会重新启动。