Description
GitHub project: SanwarJW/multi_bloc_provider
I'm facing an issue with state management and navigation in my Flutter application. I have two pages (HomePage and ImageListPage) where I'm using a bloc. I pass the bloc instance from the HomePage to the ImageListPage. However, every time I navigate to the ImageListPage, the bloc instance seems to reload, causing unexpected behavior.
HomePageState
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
final imageListBloc = BlocProvider.of<ImageListBloc>(context);
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ImageList(
imageListBloc: imageListBloc,
)));
},
child: const Text('Go to Image List'),
),
));
}
}
ImageList
class ImageList extends StatefulWidget {
final ImageListBloc imageListBloc;
const ImageList({super.key, required this.imageListBloc});
@override
State<ImageList> createState() => _ImageListState();
}
class _ImageListState extends State<ImageList> {
@override
void initState() {
super.initState();
widget.imageListBloc.loadImages();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Image List')),
body: Center(
child: StreamBuilder<List<String>>(
stream: widget.imageListBloc.imageListStream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return Text(snapshot.data![index]);
},
);
} else {
// Handle the case when data is not available
return const Text('No data available');
}
},
),
),
);
}
}
The Flutter Bloc code below defines an ImageListBloc responsible for managing image list data. It initializes with an initial state and provides a stream of image lists. The loadImages method fetches data from DataList and emits it to the stream.
ImageListBloc
DataList dataList = DataList();
class ImageListBloc extends Bloc<ImageListEvent, ImageListState> {
ImageListBloc() : super(ImageListInitial()) {}
final _imageListController = StreamController<List<String>>.broadcast();
Stream<List<String>> get imageListStream => _imageListController.stream;
loadImages() async {
if (!_imageListController.hasListener) {
var dList = await dataList.gitListData();
_imageListController.sink.add(dList);
}
}
}
What I've Tried
- Passing the bloc instance through constructors
- Investigating navigation routes for any potential issues
- Checking if the bloc instance is being properly persisted across navigations
Expected Outcome
I expect the bloc instance to be maintained without reloading when navigating between HomePage and ImageListPage, ensuring consistent behavior and state management.
Any insights or suggestions on how to resolve this issue would be greatly appreciated. Thank you!
I don't understand the purpose of passing the
ImageListBlocinstance into theImageListwidget.I see you already added it in main()
BlocProvider<ImageListBloc>(create: (context) => ImageListBloc()), then just callcontext.read<ImageListBloc>(); to get the BLoc instance within the widget tree.And there is no use of the Bloc at all in your widget, your usage of the Bloc is just like a random class that contains the StreamController.
The
ImageListreloads every time you navigate to it because theloadImages()function is called in theinitState()method before thebuildmethod runs. As a result, there is no listener for theStreamController, and without any listeners, the data will be fetched.When you navigate back, the
ImageListwidget is disposed and its listener is removed from the stream.How to fix
My suggestion is to use the BLoc correctly, add some more state to the
ImageListStateImageListBloc(I'm using Cubit here for simple example)main()ImageListFinally, correct the navigation call