Flutter StreamBuilder удаляет старые данные при загрузке

В настоящее время у меня есть StreamBuilder, извлекающий данные из Firebase для приложения для группового обмена сообщениями. У меня есть проверка snapshot.hasData, чтобы убедиться, что есть данные перед отображением сообщений. Проблема в том, что когда setState перестраивает виджеты, он также перестраивает StreamBuilder, заставляя его отображать статическое содержимое snapshot.hasData == false до того, как снова закончит загрузку данных. Это выглядит очень плохо, потому что он загружается так быстро, что кажется, будто экран мигает на секунду при каждой перестройке.

Как мне сохранить данные, пока они перезагружаются, чтобы они не мерцали?

Есть ли способ предотвратить перестройку StreamBuilder в определенных обстоятельствах?

Спасибо!

Редактировать добавленный текущий код.

var firebaseStream;
  @override
  void initState() {
    super.initState();
    firebaseStream = Firestore.instance
        .collection('groups')
        .document(groupID)
        .collection('messages')
        .orderBy('date', descending: true)
        .limit(15)
        .snapshots();

StreamBuilder(
  stream: firebaseStream,
  builder: (context, snapshot) {
     if (!snapshot.hasData)
        return Container(
           color: Colors.red,);
        return ListView.builder(

person Sam Scolari    schedule 21.07.2020    source источник


Ответы (2)


Похоже, вы получаете данные прямо в свойстве потока StreamBuilder:

StreamBuilder(
  stream: firebase.getData(),
  ...
)

Проблема в том, что он будет создавать новый поток каждый раз, когда вызывается setState, и всегда дает начальное значение null. Вместо этого вы должны использовать StatefulWidget и создать переменную в вашем состоянии во время initState, чтобы она выполнялась только один раз. Затем используйте эту переменную в качестве свойства потока в StreamBuilder. Вот очень простой пример:

class Example extends StatefulWidget {
  Example({Key key}) : super(key: key);

  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  Stream firebaseData;

  @override
  void initState() {
    super.initState();
    firebaseData = Firebase.fetchData(); //Or whatever function you use
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: firebaseData,
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          return Text(snapshot.data);
        } else {
          return Loading();
        }
      },
    );
  }
}
person David    schedule 21.07.2020
comment
Поэтому я перенес firebase.getData () в свой метод initState под названием firebaseStream. Я поместил эту переменную в свойство потока, и теперь сообщения отображаются, но как только состояние изменяется, он перестраивает StreamBuilder и теперь остается в содержимом snapshot.hasData == false на неопределенный срок. Вы имеете в виду, что я должен создать еще один виджет с сохранением состояния только для моего конструктора потоков и вызвать его в моем основном файле? - person Sam Scolari; 21.07.2020
comment
Мой код построен точно так, как показывает ваш пример, но теперь StreamBuilder сохраняет содержимое snapshot.hasData == false после первого перестроения. StreamBuilder является потомком нескольких анимированных виджетов, если это что-то меняет. - person Sam Scolari; 21.07.2020
comment
Извините, вы можете добавить свой исходный код? Если вы используете snapshots () напрямую, кажется, вы действительно можете использовать его непосредственно в StreamBuilder. Если вы не делаете что-то странное в другом месте, не вижу, что то, что я сказал, решит это - person David; 21.07.2020
comment
Я добавил соответствующий код к своему вопросу, но вот весь мой код (довольно длинный извините), если вам нужен codehare.io/5goxJV StreamBuilder находится в строке 697, initState - 115 - person Sam Scolari; 21.07.2020
comment
Хорошо, я проверил ваш код и не вижу ничего явно неправильного в логике, но серьезно, разделите ваш код на виджеты! Не пытайтесь сделать все сразу! Это может быть причиной проблемы, хотя я не знаю. Я предлагаю вам попробовать извлечь этот StreamBuilder на отдельную страницу и просто отобразить его вывод, чтобы проверить, не вызывает ли он по-прежнему проблем. - person David; 21.07.2020
comment
Ok. Без проблем! - person David; 21.07.2020

Вы пробовали использовать состояние snapshot.Connection?

@override
      Widget build(BuildContext context) {
        return StreamBuilder(
          stream: firebaseData,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (snapshot.connectionState == ConnectionState.active && snapshot.hasData) {
final data = snapshot.data;
              return Text(data);
            } else if (snapshot.connectionState == ConnectionState.waiting) {
              return Loading(); // OR CircularProgressIndicator()
            } else // Handle error here.
          },
        );
      }
person Gareth Beall    schedule 21.07.2020
comment
Это не меняет текущего состояния моей проблемы. Спасибо. - person Sam Scolari; 22.07.2020