BLoC: listen callback called multiple times

3,460

When you add a new Widget in your Navigator avoid creating that widget inside the builder, instead declare a variable outside and reuse that variable in your builder, like this:

final page = Page();
Navigator.of(context).push(MaterialPageRoute(
                            builder: (BuildContext context) => page ), );

With this change we avoid that our widget is recreated many times in an unexpected way.

Share:
3,460
Cosimo Sguanci
Author by

Cosimo Sguanci

Updated on December 11, 2022

Comments

  • Cosimo Sguanci
    Cosimo Sguanci over 1 year

    I have a Stateful Widget which obtains a bloc from its parent:

    class Page extends StatefulWidget {
      @override
      State<StatefulWidget> createState() =>
      _PageState();
    }
    
    class _PageState extends State<Page> {
      final TextEditingController mnemonicController = TextEditingController();
      final _scaffoldKey = GlobalKey<ScaffoldState>();
    
      @override
      Widget build(BuildContext context) {
    
    final MnemonicLogicBloc mnemonicLogicBloc =
    BlocProvider.of<MnemonicLogicBloc>(context);
    
    mnemonicLogicBloc.outCheckMnemonic.listen((isCorrect){
      if (!isCorrect) {
        SnackBar copySnack = SnackBar(content: Text('Wrong Mnemonic!'));
        _scaffoldKey.currentState.showSnackBar(copySnack);
      }
    });
    
    return Scaffold(
        key: _scaffoldKey,
        body: Container(
          width: double.infinity,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Container(
                child: TextField(
                  controller: mnemonicController,
                ),
              ),
              RaisedButton(
                onPressed: () {
                  mnemonicLogicBloc.isMnemonicCorrect(mnemonicController.text);
                },
                child: Text('Check', style: TextStyle(color: Colors.white)),
              )
            ],
          ),
        ));
    }
    }
    

    What I want to do is to check, when user press the button, if the string inserted is correct. The method I call in the bloc is:

    void isMnemonicCorrect(String typedMnemonic){
    if(typedMnemonic == _lastGeneratedMnemonic)
      _inCheckMnemonic.add(true);
    else
      _inCheckMnemonic.add(false);
     }
    

    _inCheckMnemonic is the Sink of my Subject (I'm using rxDart), while outCheckMnemonic is my Stream. The problem is that, even though the bloc's 'isCorrect' method is called once, the listen callback is called twice (The SnackBar is shown twice). Why does this happen?

    EDIT: I navigate to Page() simply using Navigator.push:

    Navigator.of(context).push(MaterialPageRoute(
                                builder: (BuildContext context) {
                    return Page();
    }));
    

    I'm able to retrieve the bloc because, when my app start I initialized the bloc:

    return runApp(BlocProvider<ApplicationBloc>(
    bloc: ApplicationBloc(),
    child: BlocProvider<MnemonicLogicBloc>(
      bloc: MnemonicLogicBloc(),
      child: BlocProvider<HomePageBloc>(
        bloc: HomePageBloc(),
        child: App(),
      ),
    )
    

    ));

    • diegoveloper
      diegoveloper almost 5 years
      add the code when you call your Page widget
    • Cosimo Sguanci
      Cosimo Sguanci almost 5 years
      @diegoveloper done
    • diegoveloper
      diegoveloper almost 5 years
      try doing this change, declare your Page() as a variable outside your builder: function, and just use the variable then. final page = Page(); Navigator.of .... builder: (BuildContext context) => page ) .... and check if it works
    • Cosimo Sguanci
      Cosimo Sguanci almost 5 years
      It seems to work now. But why?
    • Rémi Rousselet
      Rémi Rousselet almost 5 years
      You're falling for stackoverflow.com/questions/52249578/…. The way you use BlocProvider is unsafe and you're expected to make a stateful widget instead.
    • Cosimo Sguanci
      Cosimo Sguanci almost 5 years
      @RémiRousselet are you talking about the bloc.isMnemonicCorrect method call?
  • Code Spirit
    Code Spirit about 4 years
    But doesnt this also take up all the memory and other resources?