这发生在我的主应用程序中 和 我用给定的代码实验室复制它: 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>";
}
我唯一使用的插件是 cloud_firestore 0.9.5 + 2 。请耐心等待此测试过程。您不会立即看到该问题。首先运行应用程序,设置该项目。您可以按照给定的代码实验室中的说明进行操作。一旦一切都设置在前端和后端(在firstore上创建文档)。去吃午饭,晚餐,玩视频游戏或和朋友一起出去玩。 1小时后再回来。运行该应用,您将被收取新的阅读费用。再做一次,回来1个小时,它将再次发生
如何在现实生活中复制它: 通过代码实验室中的给定代码启动此应用。运行它,如果您将4个文档存储到Firestore中,则会导致读取4个文档。
再次启动。不收取任何费用。太棒了!但是不,真的没有。
我第二天醒来,打开应用程序,读取4次。好吧,也许有些魔术发生了。我立即重新启动它,没有任何费用产生(很棒!)。 稍后,我会在1小时内启动该应用程序,并收取4次读取费用,以显示完全相同的4个文档。
问题是,在应用程序启动时。似乎是从查询快照下载文档。没有对文档进行任何更改。这个流生成器以前已经运行了很多次。
离线模式(飞行模式),显示的缓存数据没有问题。
例如,在我的主应用程序中,我有一个photoUrl,并且在重新启动App时,您可以看到它是从firestore中加载的(意味着将其下载为新文件,从而产生READ费用)。我重新启动主应用程序,不收费,照片也不刷新(太好了!)。 1小时后,我启动了该应用程序,并对检索到的每个文档收取费用(未更改)。
这应该是Cloud Firestore的行为方式吗? 根据我的阅读,它不应该表现为:(
答案 0 :(得分:0)
除了构建窗口小部件树之外,您不应在build()
中进行实际工作
代替构建中的此类代码
stream: Firestore.instance.collection('baby').snapshots(),
您应该使用
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);
},
);
}
FutureBuilder文档没有明确提及,但完全相同
https://docs.flutter.io/flutter/widgets/FutureBuilder-class.html
将来一定要早一些,例如中 State.initState,State.didUpdateConfig或 State.didChangeDependencies。不得在 构造状态时调用State.build或StatelessWidget.build方法 FutureBuilder。如果未来与 FutureBuilder,那么每次重新构建FutureBuilder的父项时, 异步任务将重新启动。
答案 1 :(得分:0)
Also, if the listener is disconnected for more than 30 minutes (for example, if the user goes offline), you will be charged for reads as if you had issued a brand-new query.
https://firebase.google.com/docs/firestore/pricing
我想我正在面对这个。 30分钟(我已经对其进行了多次测试),我可以启动我的应用,并且不计入读取次数。等待(关闭应用程序>)30〜35分钟后,我再次启动应用程序,并对查询中的每个文档收费。
现在,如果我保持监听器处于打开状态(而不是关闭其订阅),则应该避免这种情况,而是下载经过修改的文档。
我尝试过:
List<DocumentSnapshot> nameDocs = [];
StreamSubscription nameSub;
@override
void initState() {
super.initState();
nameSub = Firestore.instance.collection('baby').snapshots().listen((data) {
print('listener Fired at line 39 main.dart');
data.documentChanges.forEach((x) {
print('${x.type} this is the type line 40');
if (x.type == DocumentChangeType.modified) {
print('modified');
nameDocs.removeAt(x.oldIndex);
setState(() {
nameDocs.add(x.document);
});
}
if (x.type == DocumentChangeType.added) {
print('added');
setState(() {
nameDocs.add(x.document);
});
}
if (x.type == DocumentChangeType.removed) {
print('removed');
setState(() {
nameDocs.removeAt(x.oldIndex);
});
}
print(x.document.data['name']);
});
});
}
我不取消订阅,因为我不想取消订阅。在31分钟后重新访问该应用程序后,发生相同的问题。
有没有办法让听众保持活力,我知道有些缺点可能是电池寿命,而有些则不行。我想在应用程序的某些部分保留实时监听器(例如,在Firestore中不经常更改的文档,我希望避免在 REAL 应用程序中重新下载此类文档)和其他部分将照常离开(在处理方法上侦听并取消)