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

Flutter Bloc问题:状态变更后BlocBuilder未再次调用builder方法

解决Flutter Bloc主题切换时UI不更新的问题

从你的日志和代码来看,问题的核心原因是**ThemeBloc被重复创建了**,导致状态更新的Bloc和UI监听的Bloc不是同一个实例,所以后续的状态变更无法触发BlocBuilder的重建。

问题分析

你把BlocProvider放在了_MyAppState的build方法内部:

@override
Widget build(BuildContext context) {
  return BlocProvider(
    create: (context) => ThemeBloc(),
    child: BlocBuilder<ThemeBloc, ThemeState>(...)
  );
}

当第一次切换主题时,MaterialApp的theme变化会触发MyApp的build方法重新执行,这时候会创建一个全新的ThemeBloc实例。而你的按钮点击事件获取的是之前的旧ThemeBloc实例,后续的状态更新都发送到了旧Bloc里,但UI监听的是新创建的Bloc,自然不会触发UI更新。

从日志也能看出来:第一次切换到BlueLight时builder日志打印了,之后切换到GreenDark时只有ThemeBloc的日志,没有builder的日志,说明新的Bloc没有收到状态变更,而旧Bloc的状态更新无法被新的BlocBuilder捕获。

解决方案

把BlocProvider提升到MyApp的外部,确保整个应用只有一个ThemeBloc实例,避免重复创建。具体步骤如下:

  1. 将MyApp改为StatelessWidget(或者保持StatefulWidget但把BlocProvider移到父级,避免在build方法内重复创建)
  2. 在runApp中直接包裹BlocProvider,让整个应用共享同一个ThemeBloc实例

修改后的代码示例

主入口部分

void main() {
  runApp(
    BlocProvider(
      create: (context) => ThemeBloc(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<ThemeBloc, ThemeState>(
      builder: (context, state) {
        print("builder " + state.toString());
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Bitradez',
          routes: routes,
          theme: state.themeData,
        );
      },
    );
  }
}

ThemeBloc部分(保持不变)

class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
  ThemeBloc() : super(ThemeState(themeData: appThemeData[AppTheme.GreenLight]));

  @override
  Stream<ThemeState> mapEventToState(
    ThemeEvent event,
  ) async* {
    print("ThemeBloc " + (event as ThemeChanged).theme.toString());
    if (event is ThemeChanged) {
      print("ThemeBloc isThemeChange");
      yield ThemeState(themeData: appThemeData[event.theme]);
    }
  }
}

按钮点击事件(保持不变)

onTap: () {
  print("_ChangeThemeScreenState " + itemAppTheme.toString());
  BlocProvider.of<ThemeBloc>(context)
     .add(ThemeChanged(theme: itemAppTheme));
},

为什么这样能解决问题

现在ThemeBloc只在应用启动时创建一次,所有UI组件(包括BlocBuilder和按钮)都共享同一个Bloc实例。当按钮发送事件更新状态时,BlocBuilder会监听同一个Bloc的状态变化,每次状态变更都会触发builder方法重新执行,UI也会随之更新。

内容的提问来源于stack exchange,提问作者Đăng Huấn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 17:47:58