Flutter生成路由如何通过BlocProvider.value实现Bloc懒实例化?
方案1:懒实例化+同Router生命周期绑定
这种方案改造成本最低,Bloc只会在第一次被访问的时候实例化,后续同路由栈内的所有对应路由都复用同一个实例,适合需要Bloc在整个App生命周期内留存的场景:
class AppRouter { // 改为可空懒声明,不提前实例化 CounterBloc? _counterBloc; // 通过getter实现首次访问时才初始化 CounterBloc get counterBloc { _counterBloc ??= CounterBloc(); return _counterBloc!; } Route onGenerateRoute(RouteSettings settings) { switch (settings.name) { case '/': return MaterialPageRoute( builder: (_) => HomePage(), ); // 只有首次进入/counter相关路由时才会触发Bloc实例化 case '/counter': return MaterialPageRoute( builder: (_) => BlocProvider.value( value: counterBloc, child: CounterPage(), ), ); case '/counter/detail': return MaterialPageRoute( builder: (_) => BlocProvider.value( value: counterBloc, child: CounterDetailPage(), ), ); default: return MaterialPageRoute(builder: (_) => const UnknownPage()); } } // 新增销毁方法,避免内存泄漏 void dispose() { _counterBloc?.close(); } }
注意使用该方案时,需要在App根Widget的State中持有AppRouter实例,并在dispose生命周期调用销毁方法:
class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final AppRouter _router = AppRouter(); @override Widget build(BuildContext context) { return MaterialApp( onGenerateRoute: _router.onGenerateRoute, ); } @override void dispose() { _router.dispose(); super.dispose(); } }
方案2:路由组绑定生命周期,退出自动销毁Bloc
如果你需要Bloc只在访问特定路由组的时候存在,退出整个路由组(比如从/counter退回到首页)就自动销毁释放资源,可以用嵌套BlocProvider的方式,完全自动管理生命周期,扩展性最好:
class AppRouter { Route onGenerateRoute(RouteSettings settings) { switch (settings.name) { case '/': return MaterialPageRoute( builder: (_) => HomePage(), ); case '/counter': // 首次进入/counter路由时才实例化Bloc,包裹在路由组根节点 return MaterialPageRoute( builder: (_) => BlocProvider( create: (context) => CounterBloc(), child: const CounterPage(), ), ); case '/counter/detail': // 子路由直接从父路由上下文读取Bloc,无需重复实例化 return MaterialPageRoute( builder: (context) => BlocProvider.value( value: context.read<CounterBloc>(), child: const CounterDetailPage(), ), ); default: return MaterialPageRoute(builder: (_) => const UnknownPage()); } } }
该方案不需要手动管理Bloc销毁,当/counter路由被完全pop出栈时,Bloc会被框架自动close,完全符合「仅访问对应路由时才实例化」的要求。
内容的提问来源于stack exchange,提问作者Enzo Dtz
相关产品推荐
相关产品推荐

