Как использовать StreamBuilder в ящике?

#android #flutter

#Android #флаттер

Вопрос:

Я внедряю виджет выхода из системы, который будет отображаться только при входе пользователя в систему. Я использовал этот DrawerLogout виджет внутри Drawer с ListView

 class DrawerLogout extends StatefulWidget {
  @override
  _DrawerLogoutState createState() => _DrawerLogoutState();
}

class _DrawerLogoutState extends State<DrawerLogout> {
  Stream authState = FirebaseAuth.instance.authStateChanges();

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: authState,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListTile(
              title: Text(
                'Logout',
                style: TextStyle(color: Theme.of(context).errorColor),
              ),
              onTap: () {
                FirebaseAuth.instance.signOut();
              },
            );
          }
          return Container();
        });
  }
}
 

Что-то вроде этого:

 Scaffold(
drawer: Drawer(
child: ListView(
   children:[
             ...
             ...
             DrawerLogout(),
            ])
          )
         )
 

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

Это код ошибки, когда он исчезает:

 [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Bad state: Cannot add new events while doing an addStream
 

Комментарии:

1. Инициализирует ли это Stream authState = FirebaseAuth.instance.authStateChanges(); в initState() справке?

2. @JoyTerence это работает! Большое вам спасибо! Не могли бы вы использовать ответ, чтобы я мог его принять?

Ответ №1:

Как обсуждалось в комментариях, перемещение инициализации состояния initState решило проблему.

Проблема была вызвана добавлением новых событий в удаленный поток. Согласно документам:

Если метод построения состояния зависит от объекта, который сам может изменять состояние, например, ChangeNotifier или Stream, или какого-либо другого объекта, на который можно подписаться для получения уведомлений, то обязательно правильно подписывайтесь и отменяйте подписку в initState , didUpdateWidget и dispose:

  • В initState подпишитесь на объект.
  • В didUpdateWidget отпишитесь от старого объекта и подпишитесь на новый, если обновленная конфигурация виджета требует замены объекта.
  • В dispose отпишитесь от объекта.

Ответ №2:

Как и предполагал @JoyTerence, инициализация потока в initState работает!

 class DrawerLogout extends StatefulWidget {
  @override
  _DrawerLogoutState createState() => _DrawerLogoutState();
}

class _DrawerLogoutState extends State<DrawerLogout> {
  Stream authState;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    authState = FirebaseAuth.instance.authStateChanges();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: authState,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListTile(
              title: Text(
                'Logout',
                style: TextStyle(color: Theme.of(context).errorColor),
              ),
              onTap: () {
                FirebaseAuth.instance.signOut();
              },
            );
          }
          return Container();
        });
  }
}