Cloud Firestore продолжает перезагружать документы - Flutter - PullRequest
1 голос
/ 06 марта 2019

это происходит в моем основном приложении а также Я повторяю это с данными кодовыми метками: 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 . Вам необходимо набраться терпения в этом процессе тестирования, пожалуйста. Вы не увидите проблему сразу. Сначала запустите приложение, настройте этот проект. Вы можете следовать указаниям в данных коде. Как только все настроено на передний конец и на задний план (создайте документы в первом магазине). Сходите на обеденный перерыв, поужинайте, поиграйте в видеоигры или пообщайтесь с друзьями. Вернись через 1 час. Запустите приложение, вы будете платить за эти чтения как новые. Сделай это снова, вернись через 1 час, и это случится снова

Как повторить это в реальной жизни: Запустите это приложение по заданному коду из codelabs. Запустите его, должно произойти 4 чтения документа, если вы сохранили 4 документа в пожарном депо.

Запустите его снова. Нет чтения не взимается. Отлично, это работает! но нет, это действительно не так.

Я просыпаюсь на следующий день и открываю приложение, я заряжен за 4 чтения. Хорошо, возможно, произошло какое-то волшебство. Я перезагружаю его сразу же, и никаких расходов не возникает (отлично!). Спустя 1 час я запускаю приложение, и мне платят 4 чтения, чтобы отобразить те же 4 документа, которые не были изменены вообще.

Проблема в том, что приложение запускается. Похоже, загрузка документов из снимка запроса. Никаких изменений не было внесено в документы. Этот построитель потоков ранее запускался много раз.

Автономный режим (режим самолета), кэшированные данные отображаются без проблем.

в моем основном приложении, например, у меня есть photoUrl, и при новом запуске приложения вы можете видеть, как он загружается из пожарного хранилища (то есть загружается как свежий документ, таким образом, взимается плата READ). Я перезагружаю свое основное приложение, никаких начислений и фото не обновляется (отлично!). Через 1 час я запускаю приложение и взимаю плату за каждый извлеченный документ (ничего не изменилось).

Так должен вести себя облачный пожарный магазин? Из того, что я прочитал, не должно быть так: (

Ответы [ 2 ]

0 голосов
/ 08 марта 2019
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 ) и другие части, которые я буду оставить как обычно (прослушать и отменить при утилизации метод)

0 голосов
/ 06 марта 2019

Вы не должны выполнять фактическую работу в 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 перестраивается, асинхронная задача перезапускается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...