Ограничение StreamBuilder - PullRequest
       12

Ограничение StreamBuilder

0 голосов
/ 27 февраля 2019

StreamBuilder перестраивается при получении нового события.Это вызывает проблемы, например, с навигацией (Navigator.push), потому что, если новое событие получено во время навигации, этот триггер перестраивается.Поскольку попытаться перемещаться, пока дерево виджетов все еще строится, это выдаст error .

невозможно предотвратить перестроение , чтобы избежать этой проблемы по мере необходимости.

Предлагаемый обходной путь - это, как правило, получение потока из кэша .Также: здесь и здесь

Но это значение не может иметь список сборки StreamBuilder, который постоянно обновляется, если также требуется обеспечить навигацию по картам в списке.Например, в карточке onPressed(). См. Здесь .

Итак, чтобы обновить данные, необходимо использовать pull для обновления ...

У кого-нибудь есть лучшее решение?Или команда Flutter работает над устранением этого ограничения, например, разрешением запретить восстановление, если карта была нажата пользователем?

ОБНОВЛЕНИЕ:

TL; DR - обновление только для обновления данных с момента потокав StreamBuilder должен быть кэширован, чтобы предотвратить его перестройку при каждом получении нового события?

ОБНОВЛЕНИЕ 2:

Я пытался реализовать данные кэша, но мой код не работает:

Stream<QuerySnapshot> infoSnapshot;

fetchSnapshot()  {
  Stream<QuerySnapshot> infoSnapshot = Firestore.instance.collection(‘info’).where(‘available’, isEqualTo: true).snapshots();
  return infoSnapshot;
}


  @override
  void initState() {
    super.initState();
  fetchSnapshot();
  }

...

child: StreamBuilder(
stream: infoSnapshot,
builder: (context, snapshot) {

if(snapshot.hasData) {
   return ListView.builder(
        itemBuilder: (context, index) =>
            build(context, snapshot.data.documents[index]),
        itemCount: snapshot.data.documents.length,
     );
  } else {
      return _emptyStateWidget();
  }

ОБНОВЛЕНИЕ 3:

Я пытаюсь использовать StreamController, но не могу правильно выполнить:

Stream<QuerySnapshot> infoStream;
StreamController<QuerySnapshot> infoStreamController = StreamController<QuerySnapshot>();

  @override
  void initState() {
    super.initState();

  infoStream = Firestore.instance.collection(‘info’).where(‘available’, isEqualTo: true).snapshots();
  infoStreamController.addStream(infoStream);
  }

child: StreamBuilder(
stream: infoStreamController.stream,
builder: (context, snapshot) {

ОБНОВЛЕНИЕ 4:

Предложение использовать _localStreamController выдавать ошибку:

StreamController<QuerySnapshot> _localStreamController = StreamController<QuerySnapshot>();

  @override
  void initState() {
    super.initState();

Firestore.instance.collection(‘info’).snapshots().listen((QuerySnapshot querySnapshot) {

//      if(userAdded == null) {
        _localStreamController.add(querySnapshot);
//      }

    });
...
child: StreamBuilder(
stream: _localStreamController.stream,
builder: (context, snapshot) {

Получатель 'stream' был вызван для нуля.

Метод 'add' был вызван для нуля.

Ответы [ 2 ]

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

Попробуйте разбить все на виджеты

Выполнение запроса должно кэшировать его, даже если вы полностью закроете свое приложение (я считаю, что кэшировать его можно только при полностью закрытом состоянии до 30 минут, но если выостаются без подключения к интернету, у вас все еще есть доступ к прошлым предыдущим кэшированным запросам из Firestore )

Попробуйте что-то вроде этого:

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Please work')),
      body: _buildStream(context),
    );
  }

  Widget _buildStream(BuildContext context) {
     return StreamBuilder(
      stream: yourFireStoreStream,
      builder: (context, snapshot) {
        if (!snapshot.hasData) return LinearProgressIndicator();

        return _buildAnotherwidget(context, snapshot.data.documents);
      },
    );
  }
  Widget _buildAnotherwidget(Buildcontext context, List<DocumentSnapshot> snaps){
    return ListView.Builder(
      itemCount: snaps.length,
      itemBuilder:(context, index) {
      ..dostuff here...display your cards etc..or build another widget to display cards
         }
     );
 }

сосредоточиться на взломе большего количества виджетов,Самая высокая часть должна иметь построитель потока вместе с потоком.затем углубиться в больше виджетов.Streambuilder автоматически прослушивает и подписывается на данный поток.

При обновлении streambuilder обновляются нижние виджеты.

Теперь, когда вы нажимаете на карту в нижнем виджете, чтобынавигация, это не должно влиять на самый высокий виджет, потому что это повлияет только на пользовательский интерфейс.

мы поместили streambuilder в его собственный виджет верхнего уровня ...

Надеюсь, у меня был какой-то смысл :(

Я написал код без тестирования, но я уверен, что вы можете заставить его работать

0 голосов
/ 28 февраля 2019

Кажется, что реальная проблема, основанная на ваших комментариях выше, состоит в том, что она вылетает после того, как вы удалились из представления, используя поток.Вы должны либо:

  • Отменить контроллер потока, когда вы уходите, чтобы он не прослушивал больше никаких событий.
  • Или просто не передавать новые значения через потокпосле навигации.Добавляйте паузу, пока не вернетесь к представлению

Обновление: добавление кода с псевдо-примером

class Widget {
  // Your local stream 
  Stream<String> _localStream;
  // Value to indicate if you have navigated away
  bool hasNavigated = false;
  ...
  void init() {
    // subscribe to the firebase stream
    firebaseStream...listen((value){
      // If this value is still false then emit the same value to the localStream
      if(!hasNavigated) {
        _localStream.add(value);
      }
    });
  }

  Widget build() {
    return StreamBuilder(
      // subscribe to the local stream NOT the firebase stream
      stream: _localStream,
      // handle the same way as you were before
      builder: (context, snapshot) {
         return YourWidgets();
      }
    );
  }
}
...