You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:52:34