Нумерация страниц в флаттере с базой данных Firebase Realtime - PullRequest
0 голосов
/ 31 января 2019

Я пытаюсь разбить страницу во Флаттере с помощью базы данных в реальном времени.Я пробовал это в Firestore, и там он работает нормально, но я хочу это с базой данных в реальном времени.

Я получаю данные в первый раз, как это.

 Widget buildListMessage() {
    return Flexible(
      child: StreamBuilder(
        stream: _firebase.firebaseDB
            .reference()
            .child("chats")
            .child("nsbcalculator")
            .orderByChild('timestamp')
            .limitToFirst(15)
            .onValue,
        builder: (context, AsyncSnapshot<Event> snapshot) {
          if (!snapshot.hasData) {
            return Center(
                child: CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation<Color>(themeColor)));
          } else {

            if (snapshot.data.snapshot.value != null) {

                listMessage = Map.from(snapshot.data.snapshot.value)
                    .values
                    .toList()
                      ..sort(
                          (a, b) => a['timestamp'].compareTo(b['timestamp']));

              if (lastVisible == null) {
                lastVisible = listMessage.last;
                listMessage.removeLast();
              }
            }

            return ListView.builder(
              ...
            );
          }
        },
      ),
    );
  }

После этого, чтобы разбить на страницы, яЯ использую прослушиватель с ScrollController

  void _scrollListener() async {
    if (listScrollController.position.pixels ==
        listScrollController.position.maxScrollExtent) {
      _fetchMore();
    }
  }

и, наконец,

  _fetchMore() {
    _firebase.firebaseDB
        .reference()
        .child("chats")
        .child("nsbcalculator")
        .orderByChild('timestamp')
        .startAt(lastVisible['timestamp'])
        .limitToFirst(5)
        .once()
        .then((snapshot) {

      List snapList = Map.from(snapshot.value).values.toList()
        ..sort((a, b) => a['timestamp'].compareTo(b['timestamp']));


      if (snapList.isNotEmpty) {
        print(snapList.length.toString());

        if (!noMore) {

          listMessage.removeLast();

          //Problem is here.....??
          setState(() {
            listMessage..addAll(snapList);
          });

          lastVisible = snapList.last;

          print(lastVisible['content']);
        }

        if (snapList.length < 5) {
          noMore = true;
        }
      }
    });
  }

Он работает нормально, как связь в реальном времени, но когда я пытаюсь разбить на страницы в _fetchMore (), вызывается setState, но он обновляет состояниевсего виджета и перезапускает StreamBuilder снова, и все данные заменяются только новым запросом.Как я могу предотвратить это ??

1 Ответ

0 голосов
/ 31 января 2019

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

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

final _list = List<Event>();
final _listController = StreamController<List<Event>>.broadcast();
Stream<List<Event>> get listStream => _listController.stream;

@override
void initState() {
  super.initState();
  // Here you need to load your first page and then add to your stream
  ...
  _list.addAll(firstPageItems);
  _listController.sink.add(_list);
}

@override
void dispose() {
  super.dispose();
}

Widget buildListMessage() {
    return Flexible(
      child: StreamBuilder(
        stream: listStream
        ...
}

_fetchMore() {
  ...
  // Do your fetch and then just add items to the stream
  _list.addAll(snapList);
  _listController.sink.add(_list);
  ...
}

...