Доступ к потоку внутри вложенного StreamBuilder во Flutter

У меня возникла проблема с вызовом StreamBuilder внутри другого StreamBuilder, который находится внутри поля onPressed виджета RasedButton. По сути, я пытаюсь получить доступ к потоку (после добавления в него данных) внутри внутреннего StreamBuilder, но выполнение не вызывает эту часть кода:

Widget submitButton(BuildContext ctx, AccountBloc bloc){
   return StreamBuilder(
      stream: bloc.submitValid,
      builder: (context, snapshot){
        return SizedBox(
          width: double.infinity,
          height: 60,
          child: RaisedButton(
            color: HexColor("0072b1"),
            child: Text("Sign in", style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 20,
              color: Colors.white
            ),
            ),
            onPressed:() {
               if(snapshot.hasData){
                 bloc.loginUser();
             
                 // DEBUGGING
                 print(bloc.isAuthenticated.listen((val) { print("debug isAuthenticated: $val"); }));
                  StreamBuilder(
                     stream: bloc.isAuthenticated,
                     builder: (ctx, snapshotA){
                       print("here");
                       if(!snapshotA.hasData){
                         return Text("loading....");
                       }
                       print("***${snapshotA.data}****");
                       if(snapshotA.data == false){
                         return navSignUpScreen(ctx);
                       }else if (snapshotA.data == false){
                         print("here");
                         return navHomeScreen(ctx);
                       }
                       return navSignUpScreen(ctx);
                     }
                 );
               }
            },
          ),
        );
      }
  );
}

Часть BLOC выглядит следующим образом:

  final _isAuthenticated = BehaviorSubject<bool>();
  Stream<bool> get isAuthenticated => _isAuthenticated.stream;

  void loginUser() async {
    var inMemory = InMemoryProvider();
    inMemory.newInMemoryProvider();

    UserModel userResult = await _repository.loginUser(_email.value, _password.value);
    if(userResult.status == 200){
      // save TOKEN
      UserModel userModel = UserModel.fromJsonToModel(userResult.data);
      bool res =  await inMemory.store(userModel.id, userModel.token);
      _isAuthenticated.sink.add(res);
    }
    _userLoginResponse.sink.add(userResult);
  }

Определение navHomeScreen очень простое:

class HomeScreen extends StatefulWidget {
  createState() {
    return HomeState();
  }
}


class HomeState extends State<HomeScreen> {

  int _currentIndex = 0;

  final List<Widget> _children = [
    AllReportsScreen(), UserProfileScreen()
  ];

  Widget build(context) {
    return Scaffold(
      body: _children[_currentIndex],
      bottomNavigationBar: mainBottomNavigatorBar(),
    );
  }

  Widget mainBottomNavigatorBar() {
    return BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      onTap: onTabTapped,
      currentIndex: _currentIndex,

      items: [
        BottomNavigationBarItem(
          backgroundColor: Colors.black45,
          icon: new Icon(Icons.note),
          title: new Text('Reports', style: TextStyle(fontSize: 15.0)),
        ),
        BottomNavigationBarItem(
          backgroundColor: Colors.black45,
          icon: new Icon(Icons.label_important),
          title: new Text('Attention', style: TextStyle(fontSize: 15.0)),
        ),

        BottomNavigationBarItem(
          backgroundColor: Colors.black45,
          icon: new Icon(Icons.person_pin),
          title: new Text('Profile', style: TextStyle(fontSize: 15.0)),
        ),
      ],
    );
  }


  void onTabTapped(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

}

person Deshola    schedule 31.08.2020    source источник
comment
почему вы возвращаете виджет внутри onPressed ()? Ничего не делает   -  person Uni    schedule 31.08.2020
comment
Я в основном возвращаю класс. Пожалуйста, какой подход лучше? Кроме того, вызывает беспокойство то, что внутренний StreamBuilder вообще не запускается.   -  person Deshola    schedule 31.08.2020
comment
он определенно не будет работать вообще. вы не можете отображать виджеты внутри onPressed. Вместо этого вы можете разместить StreamBuilder ниже streambuilder вверху и отобразить нижний streambuilder, когда вы нажмете на streambuilder вверху.   -  person Uni    schedule 31.08.2020
comment
Спасибо @Uni. Но не могли бы вы поделиться фрагментом кода, как это можно сделать? Насколько я понимаю, перемещение внутреннего StreamBuilder прямо над RaisedButton также не сработает, поскольку я пробовал это только сейчас.   -  person Deshola    schedule 31.08.2020
comment
У меня нет фрагмента кода о том, как это делается, но все, что я предлагаю, это что у вас есть что-то вроде этого: Column ([StreamBuilder (), StreamBuilder (этот streambuilder отобразит то, что вы хотите, при нажатии кнопки)])   -  person Uni    schedule 31.08.2020
comment
О, теперь я понимаю ваше предложение. Но проблема здесь в том, что внешний StreamBuilder должен работать с Widget (в данном случае RaisedButton). Другими словами, он проверяет потоки данных, поступающих в поля формы, и отправляет их. Перемещение внутреннего верха StreamBuilder вызовет здесь проблему.   -  person Deshola    schedule 31.08.2020
comment
Кроме того, внутренний StreamBuilder должен вызываться при нажатии кнопки. Это означает, что его нужно вызывать внутри поля onPressed объекта RaisedButton. Вот только я чего-то упускаю.   -  person Deshola    schedule 31.08.2020
comment
Если это так, то почему вы используете Streambuilder для выполнения функций? Вы можете выполнять свои функции с помощью слушателей   -  person Uni    schedule 31.08.2020
comment
Проблема в том, что сам внутренний StreamBuilder не вызывается. Использование StreamBuilder уже прослушивает поток данных. Я не понимаю, почему это проблема.   -  person Deshola    schedule 31.08.2020
comment
внутренний streambuilder не вызывается, потому что это виджет. Вы не должны иметь виджеты внутри функций для выполнения ваших функций.   -  person Uni    schedule 31.08.2020
comment
Спасибо за предложения, @Uni. Я решил эту проблему, избавившись от внутреннего StreamBuilder и просто послушав метод блока isAuthenticated внутри тела onPressed. Это аккуратно и хорошо работает. Теперь мне нужно беспокоиться о сообщениях об ошибках, если они есть. Но сейчас мне хорошо.   -  person Deshola    schedule 31.08.2020


Ответы (1)


Использование combineLatest из rxdart для объединения двух Streams isAuthenticated и submitValid в один Stream:

class LoginState {
    final bool isAuthenticated;
    final bool submitValid;
}

final state$ = Rx.combineLatest(
    bloc.isAuthenticated,
    bloc.submitValid,
    (isAuth, valid) => LoginState(isAuth, valid),
);

StreamBuilder<LoginState>(
    stream: state$,
    builder: (context, snapshot) {
        final state = snapshot.data;
        if (state == null) return ...;
        if (!state.submitValid) return ...;
        if (state.isAuthenticated) return ...;
    }
)
person Petrus Nguyễn Thái Học    schedule 04.09.2020