I'm following BLoC pattern and subscribing to stream, and reacting to state changes in build method. When data is loaded I want to close the screen.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bloc'),
),
body: SafeArea(
child: StreamBuilder<UserState>(
stream: _userBloc.user,
initialData: UserInitState(),
builder: (context, snapshot) {
if (snapshot.data is UserInitState) {
return _buildInit();
}
if (snapshot.data is UserDataState) {
Navigator.pop(context, true);
return Container();
}
if (snapshot.data is UserLoadingState) {
return _buildLoading();
}
},
),
),
);
}
When I do Navigator.pop(context, true);
in build()
method I get:
I/flutter ( 4360): ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4360): The following assertion was thrown while notifying status listeners for AnimationController:
I/flutter ( 4360): setState() or markNeedsBuild() called during build.
I/flutter ( 4360): This Overlay widget cannot be marked as needing to build because the framework is already in the
I/flutter ( 4360): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter ( 4360): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter ( 4360): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter ( 4360): Otherwise, the framework might not visit this widget during this build phase.
What is the right way to handle such cases in BLoC pattern?
On of the solutions I come up with is to start listening to stream on initState()
. In this case I need to broadcast()
my stream because I have 2 subscribers.
Are there any better solutions for this?
I think I have got a solution for you. (Please check it)
Make your code look like :
Widget build(BuildContext context) {
// other stuff
if (snapshot.data is UserDataState) {
myCallback(() {
Navigator.pop(context, true);
});
}
// other stuff
}
// after build method (but still in the same class,...) write below method
void myCallback(Function callback) {
WidgetsBinding.instance.addPostFrameCallback((_) {
callback();
});
}
Hope it helps. Just try it and please report here to help others too!
Source (flutter_bloc Login medium article)
Description
bool hasPop = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bloc'),
),
body: SafeArea(
child: StreamBuilder<UserState>(
stream: _userBloc.user,
initialData: UserInitState(),
builder: (context, snapshot) {
if (snapshot.data is UserInitState) {
return _buildInit();
}
if (snapshot.data is UserDataState) {
if(!hasPop){
hasPop = true;
Navigator.pop(context, true);
}
return Container();
}
if (snapshot.data is UserLoadingState) {
return _buildLoading();
}
},
),
),
);
} ```
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With