Как изменить заголовок AppBar: значение без повторного запуска FirebaseAnimatedList

Я использую FirebaseAnimatedList в приложении чата Flutter / Dart. Упрощенный метод build () выглядит следующим образом:

@override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: AppBar(
          title: Text(_onLineStatus), // <-- This text value changed using setState()
        ),
        body: Column(
          children: <Widget>[
            Flexible(
              child: FirebaseAnimatedList(
                query: reference,
                sort: (a, b) => b.key.compareTo(a.key),
                padding: EdgeInsets.all(8.0),
                reverse: true,
                itemBuilder: (BuildContext context, DataSnapshot snapshot,
                    Animation<double> animation, int index) {
                  return ChatMessage(snapshot: snapshot, animation: animation);
                },
              ),
            ),
            Divider(height: 1.0),
            Container(
              decoration: BoxDecoration(color: Theme.of(context).cardColor),
              child: _buildTextComposer(),
            )
          ],
        ));
  }

Я хочу изменить значение _onLineStatus в строке 5 на основе значения события, возвращаемого слушателем, в основном, чтобы указать, включен ли другой участник чата или отключен. Я хочу, чтобы любое изменение статуса отражалось немедленно. Очевидный способ сделать это - использовать setState (), но, конечно, это вызывает полный повторный запуск метода build (), который, следовательно, повторно запускает запрос FirebaseAnimatedList, снова загружая те же данные. Я хочу этого избежать.

Все примеры использования FirebaseAnimatedList показывают его как часть метода build (), однако нам рекомендуется избегать помещения вызовов базы данных в build (), чтобы избежать этих побочных эффектов, поскольку build () может запускаться несколько раз.

Поэтому мои вопросы таковы:

  1. Как я могу переместить вызов FirebaseAnimatedList вне метода build (), чтобы я мог использовать setState () для обновления значения свойства AppBar title: БЕЗ его повторного запуска FirebaseAnimatedList?

OR...

  1. Как я могу обновить значение свойства AppBar title: без повторного запуска метода build (), т.е. без вызова setState ()?

person GrahamD    schedule 15.04.2020    source источник


Ответы (1)


Создайте StateFullWidget, содержащий панель вашего приложения. Что-то вроде этого:

Widget build(BuildContext context) {
    return new Scaffold(
        appBar: CustomAppBar(), 
        body: Column(
        ...

А затем ваш новый виджет панели приложений:

class CustomAppBar extends StatefulWidget {
  @override
  _CustomAppBarState createState() => _CustomAppBarState();
}

class _CustomAppBarState extends State<CustomAppBar> {
  String _onLineStatus = "online";

  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: Text(_onLineStatus),
    );
  }
}

таким образом вы можете самостоятельно перестроить панель приложений из списка. Вам нужно вызвать setState в новом виджете.

person jbarat    schedule 15.04.2020
comment
Спасибо за Ваш ответ. Имеет смысл. Я смогу попробовать это только завтра и вернусь к вам тогда. - person GrahamD; 15.04.2020
comment
Извините за медленный ответ. Мне пришлось переместить свой слушатель в новый виджет, чтобы вызвать setState () для изменения статуса, что привело к целому ряду других проблем, потому что мне также нужен слушатель на вызывающей странице. Так что на данный момент у меня есть два активных слушателя, которые делают то же самое. Спасибо еще раз. Кстати, ваш код возвращает вторую панель приложения, а не только заголовок панели приложения, поэтому я немного изменил его из-за моего использования. - person GrahamD; 16.04.2020
comment
Наличие нескольких слушателей - не проблема. Когда станет сложно, я бы рекомендовал изучить Provider lib. Очень полезно для государственного управления. - person jbarat; 16.04.2020
comment
Спасибо @jbarat. В настоящее время в моем приложении используется scoped_model, и я подумаю о том, чтобы заменить его Provider позже в этом году, учитывая, что scoped_model устаревает в конце 2020 года. - person GrahamD; 16.04.2020