Flutter Bloc页面切换时实例重复加载问题求助
问题解决方案
问题根源分析
- 自定义
StreamController不符合flutter_bloc的规范,且依赖监听状态判断是否加载数据,页面销毁后监听取消,再次进入会重新触发加载。 - 通过构造函数传递Bloc实例的方式不规范,容易出现实例管理混乱。
ImageList的initState每次都会调用loadImages,没有判断数据是否已加载。
1. 重构Bloc实现(遵循flutter_bloc规范)
移除自定义StreamController,改用Bloc自带的事件-状态流管理数据:
DataList dataList = DataList(); // 定义事件 abstract class ImageListEvent {} class LoadImagesEvent extends ImageListEvent {} // 定义状态 abstract class ImageListState {} class ImageListInitial extends ImageListState {} class ImageListLoading extends ImageListState {} class ImageListLoaded extends ImageListState { final List<String> images; ImageListLoaded(this.images); } class ImageListError extends ImageListState { final String error; ImageListError(this.error); } class ImageListBloc extends Bloc<ImageListEvent, ImageListState> { List<String>? _cachedImages; ImageListBloc() : super(ImageListInitial()) { on<LoadImagesEvent>(_onLoadImages); } Future<void> _onLoadImages(LoadImagesEvent event, Emitter<ImageListState> emit) async { // 缓存数据存在则直接返回,避免重复加载 if (_cachedImages != null) { emit(ImageListLoaded(_cachedImages!)); return; } emit(ImageListLoading()); try { var dList = await dataList.gitListData(); _cachedImages = dList; emit(ImageListLoaded(dList)); } catch (e) { emit(ImageListError(e.toString())); } } }
2. 在全局/父级提供Bloc实例
确保整个导航树共享同一个Bloc实例,避免传递实例的麻烦:
void main() { runApp( BlocProvider( create: (context) => ImageListBloc(), child: const MyApp(), ), ); }
3. 修改HomePage代码(无需传递Bloc)
class _HomePageState extends State<HomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const ImageList())); }, child: const Text('Go to Image List'), ), )); } }
4. 修改ImageList代码(通过BlocProvider获取实例)
用BlocBuilder监听Bloc状态,无需手动管理Stream:
class ImageList extends StatefulWidget { const ImageList({super.key}); @override State<ImageList> createState() => _ImageListState(); } class _ImageListState extends State<ImageList> { @override void initState() { super.initState(); // 仅首次进入时触发加载 BlocProvider.of<ImageListBloc>(context).add(LoadImagesEvent()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Image List')), body: BlocBuilder<ImageListBloc, ImageListState>( builder: (context, state) { if (state is ImageListLoading) { return const CircularProgressIndicator(); } if (state is ImageListError) { return Text('Error: ${state.error}'); } if (state is ImageListLoaded) { return ListView.builder( itemCount: state.images.length, itemBuilder: (context, index) { return Text(state.images[index]); }, ); } return const Text('No data available'); }, ), ); } }
内容的提问来源于stack exchange,提问作者Sanwar Jayswal
相关产品推荐
相关产品推荐

