Flutter中MultiBlocProvider下使用BlocBuilder触发断言错误如何解决?
Flutter MultiBlocProvider 深色模式切换报错修复方案
错误根本原因
该断言错误是由于组件构建过程中触发了递归状态更新导致的,具体触发点有三个:
- HydratedCubit 未提前初始化存储,懒加载时在 build 阶段读取本地缓存并触发状态更新,打断当前构建流程
- BlocProvider 配置了懒加载(
lazy: true),首次读取 ThemeCubit 时刚好在组件构建阶段,引发重复构建 - 开关组件的取值和逻辑没有和 Bloc 状态同步,使用自定义的局部变量维护开关状态,导致状态冲突引发重复构建
修复步骤
步骤1:提前初始化 HydratedCubit 依赖的存储
修改项目入口的 main 函数,完成存储初始化后再启动应用:
import 'package:path_provider/path_provider.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; void main() async { // 先初始化Flutter原生交互通道 WidgetsFlutterBinding.ensureInitialized(); // 初始化Hydrated存储 final storage = await HydratedStorage.build( storageDirectory: await getApplicationDocumentsDirectory(), ); // 注入存储实例后启动应用 HydratedBlocOverrides.runZoned( () => runApp(const MyApp()), storage: storage, ); }
需提前在 pubspec.yaml 中添加 path_provider 依赖。
步骤2:关闭 ThemeCubit 的懒加载配置
修改 main.dart 中 BlocProvider 的 lazy 参数为 false,强制 Bloc 在 Provider 创建时就完成初始化,避免构建阶段触发初始化逻辑:
BlocProvider( lazy: false, create: (context) => ThemeCubit(), ),
步骤3:修正开关组件的状态同步逻辑
不要用自定义的局部变量 newValue 维护开关状态,直接从 Bloc 中读取当前主题状态作为开关值,切换时直接使用回调返回的最新值触发状态更新:
Positioned( top: 60 - widget.offset / 2, left: 20, child: Builder(builder: (context) { // 直接从Bloc读取当前主题状态判断开关值 final isDarkMode = context.watch<ThemeCubit>().state.themeData.brightness == Brightness.dark; return Switch( value: isDarkMode, onChanged: (value) { // 使用回调返回的最新值触发主题切换 context.read<ThemeCubit>().getTheme( ThemeState(value ? AppThemes.darkTheme : AppThemes.lightTheme) ); } ); }) ),
可选优化:简化 ThemeCubit 调用逻辑
可将 ThemeCubit 中的 getTheme 方法调整为更符合语义的命名,减少入参冗余:
// 修改ThemeCubit.dart中的方法 void setTheme(bool isDark) { emit(ThemeState(isDark ? AppThemes.darkTheme : AppThemes.lightTheme)); } // 开关处调用简化为 context.read<ThemeCubit>().setTheme(value);
内容的提问来源于stack exchange,提问作者zeynab farzaneh
相关产品推荐
相关产品推荐

