BLoC: listen callback called multiple times
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.
Cosimo Sguanci
Updated on December 11, 2022Comments
-
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 almost 5 yearsadd the code when you call your
Page
widget -
Cosimo Sguanci almost 5 years@diegoveloper done
-
diegoveloper almost 5 yearstry 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 almost 5 yearsIt seems to work now. But why?
-
Rémi Rousselet almost 5 yearsYou'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 almost 5 years@RémiRousselet are you talking about the bloc.isMnemonicCorrect method call?
-
-
Code Spirit about 4 yearsBut doesnt this also take up all the memory and other resources?