Flutter BLoC是否支持匿名路由?我的示例为何可正常运行?
为什么我的BLoC在匿名路由下能正常工作?
你遇到的情况和教程不同,核心原因是BlocProvider的放置层级:
你的代码里,BlocProvider<CounterCubit>直接包裹了MaterialApp,这意味着整个应用的所有页面(包括通过匿名路由打开的SecondScreen)都处于BlocProvider的上下文范围内,自然能获取到同一个CounterCubit实例,状态也能正常共享。
而教程中导致崩溃的场景,通常是把BlocProvider放在了HomeScreen内部(而非MaterialApp外层)。这种情况下,HomeScreen是BlocProvider的子节点,当通过匿名路由跳转新页面时,新页面的上下文不在BlocProvider的覆盖范围内,调用BlocProvider.of<CounterCubit>(context)就会抛出找不到Cubit的异常。
你可以做个测试:把BlocProvider移到HomeScreen的build方法里,再跳转SecondScreen,就能复现教程中的崩溃问题。
你的代码示例
main.dart
import 'package:counter_bloc_test/logic/cubits/counter_cubit.dart'; import 'package:counter_bloc_test/frontend/screens/home_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return BlocProvider<CounterCubit>( create: (context) => CounterCubit(), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const HomeScreen(title: 'Flutter Demo Home Page', color: Colors.blue,), ), ); } }
home_screen.dart
import 'package:flutter/material.dart'; import 'package:counter_bloc_test/logic/cubits/counter_cubit.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:counter_bloc_test/frontend/screens/second_screen.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key, required this.title , required this.color}); final String title; final Color color; @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:', ), BlocConsumer<CounterCubit, CounterState>( listener: (context, state) { if(state.wasIncremented){ ScaffoldMessenger.of(context).removeCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text("Incremented"), ) ); }else{ ScaffoldMessenger.of(context).removeCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text("Decremented"), ) ); } }, builder: (context, state) { return Text( state.counterValue.toString(), style: Theme.of(context).textTheme.headlineMedium, ); }, ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ FloatingActionButton( heroTag: "btn1", onPressed: () { BlocProvider.of<CounterCubit>(context).decrement(); }, tooltip: 'Decrement', child: const Icon(Icons.remove), ), FloatingActionButton( heroTag: "btn2", onPressed: () { BlocProvider.of<CounterCubit>(context).increment(); }, tooltip: 'Increment', child: const Icon(Icons.add), ), ], ), const SizedBox(height: 24,), MaterialButton( color: widget.color, onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => const SecondScreen( title: "Second Screen", color: Colors.redAccent, ) ) ); }, child: const Text('Go to Second Page'), ) ], ), ), ); } }
second_screen.dart
import 'package:flutter/material.dart'; import 'package:counter_bloc_test/logic/cubits/counter_cubit.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class SecondScreen extends StatefulWidget { const SecondScreen({super.key, required this.title , required this.color}); final String title; final Color color; @override State<SecondScreen> createState() => _SecondScreenState(); } class _SecondScreenState extends State<SecondScreen> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.redAccent, title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:', ), BlocConsumer<CounterCubit, CounterState>( listener: (context, state) { if(state.wasIncremented){ ScaffoldMessenger.of(context).removeCurrentMaterialBanner(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text("Incremented"), ) ); }else{ ScaffoldMessenger.of(context).removeCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text("Decremented"), ) ); } }, builder: (context, state) { return Text( state.counterValue.toString(), style: Theme.of(context).textTheme.headlineMedium, ); }, ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ FloatingActionButton( heroTag: null, onPressed: () { BlocProvider.of<CounterCubit>(context).decrement(); }, tooltip: 'Decrement', child: const Icon(Icons.remove), ), FloatingActionButton( heroTag: null, onPressed: () { BlocProvider.of<CounterCubit>(context).increment(); }, tooltip: 'Increment', child: const Icon(Icons.add), ), ], ), const SizedBox(height: 24,), MaterialButton( color: widget.color, onPressed: () { Navigator.of(context).pop(); }, child: const Text('Go to First Page'), ) ], ), ), ); } }
内容的提问来源于stack exchange,提问作者Sveg
相关产品推荐
相关产品推荐

