Flutter Bloc:如何为底部栏与路由页面提供同一Cubit实例
问题描述
应用内置底部导航栏,已创建自定义路由类统一实现应用内所有页面的跳转逻辑,但底部导航栏对应的页面并未纳入该自定义路由类的管理范围。当前遇到的问题是:无法为底部导航栏承载的页面、以及自定义路由类中定义的普通页面提供同一个Cubit实例。
相关代码如下:
class UserNavScreen extends StatefulWidget { static const routeName = 'homepage_screen'; UserNavScreen(); @override State<UserNavScreen> createState() => _UserNavScreenState(); } class _UserNavScreenState extends State<UserNavScreen> { var _index = 2; final _userPages = [ const UserProfileScreen(), const UserNotificationScreen(), BlocProvider<MapCubit>( create: (context) => MapCubit( mapRepositery: MapRepositery( mapProvider: MapProvider(), ), storesRepositery: StoresRepositery( storesProvider: StoresProvider(), ), )..getStoresLocation(), child: UserMapScreen()), const UserTopTenScreen(), const UserHomepageScreen() ]; Widget build(BuildContext context) { return Scaffold( body: _userPages[_index], bottomNavigationBar: _buildNavUser(), ); } Widget _buildNavUser() { return StyleProvider( style: StyleNavBottomBar(), child: ConvexAppBar( style: TabStyle.fixedCircle, backgroundColor: Colors.white, color: Colors.grey, initialActiveIndex: _index, activeColor: Colors.green, cornerRadius: 16, curveSize: 90, height: 60, onTap: (index) { setState(() { _index = index; }); }, elevation: 2, items: const [ TabItem( icon: Icons.person, ), TabItem( icon: Icons.notifications, ), TabItem(icon: Icons.navigation), TabItem( icon: FontAwesomeIcons.medal, ), TabItem( icon: Icons.home, ), ], ), ); } } class AppRoute { Route? onGenerateRoute(RouteSettings routeSettings) { switch (routeSettings.name) { case StoreMap.routeName: final args = routeSettings.arguments as Store; return MaterialPageRoute( builder: (context) => StoreMap(store: args), ); } } }
问题根因
现有代码中MapCubit在_userPages数组内初始化,属于UserNavScreen的子树范围;而AppRoute中onGenerateRoute生成的普通页面是独立的路由栈节点,不在该BlocProvider的子树内,自然无法获取到同一个Cubit实例。
可行实现方案
- 方案1:提升Cubit的提供层级
移除_userPages中包裹UserMapScreen的BlocProvider<MapCubit>,将Cubit的创建逻辑上移到底部导航页和普通路由页共同的父节点:如果Cubit只在用户模块相关页面使用,可以把BlocProvider放在UserNavScreen的外层(即跳转进入UserNavScreen的路由构建位置);如果Cubit是全局多个模块共用,可以直接放在MaterialApp的外层。所有子节点(包括后续路由生成的页面)只要在这个Provider的子树范围内,都可以通过context.read<MapCubit>()获取到同一个实例。 - 方案2:手动传递Cubit实例
在_UserNavScreenState中初始化MapCubit实例作为状态变量,一方面传入_userPages数组中的UserMapScreen使用,另一方面在AppRoute的onGenerateRoute逻辑中,构建StoreMap这类需要依赖该Cubit的页面时,把已创建的Cubit实例通过构造参数传递给目标页面。注意要在_UserNavScreenState的dispose生命周期中调用MapCubit的close()方法释放资源,避免内存泄漏。 - 方案3:统一所有页面的路由管理
把底部导航对应的所有页面也纳入AppRoute的统一管理范围,不要在UserNavScreen中提前初始化所有页面对象存入数组。可以结合IndexedStack和路由状态监听实现底部导航切换效果,让所有页面(包括底部导航承载页、普通跳转页)的构建逻辑都走onGenerateRoute,在统一路由逻辑中控制Cubit实例的创建和共享,从根源上解决跨路由实例不一致的问题。
内容的提问来源于stack exchange,提问作者Mary
相关产品推荐
相关产品推荐

