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

使用MultiBlocProvider时无法调用Bloc事件的问题

Flutter中MultiBlocProvider管理Bloc时GeolocationBloc事件未执行的问题

我在Flutter里用MultiBlocProvider管理GeolocationBloc和WeatherInfoBloc,逻辑是先通过GeolocationBloc获取位置,再用该位置调用WeatherInfoBloc获取天气详情。但实际运行时,GeolocationBloc的LoadGeolocationEvent根本没执行,调试一直停在默认的GeolocationLoading状态。

主文件代码

Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<GeolocationBloc>(create: (context) => locator<GeolocationBloc>()),
        BlocProvider<WeatherInfoBloc>(create: (context) => locator<WeatherInfoBloc>()),
      ], child: MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      themeMode: ThemeMode.system,
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      home: const Scaffold(
        backgroundColor: Colors.white,
        body: SafeArea(
          child: WeatherInfoPage(),
        ),
      ),
    ),
    );
  }

WeatherInfoPage代码

class WeatherInfoPage extends StatefulWidget {
  const WeatherInfoPage({super.key});

  @override
  State<WeatherInfoPage> createState() => _WeatherInfoPageState();
}

class _WeatherInfoPageState extends State<WeatherInfoPage> {
  late WeatherInfoBloc _weatherInfoBloc;
  late GeolocationBloc _geolocationBloc;
  
  @override
  void initState() {
    super.initState();
    _weatherInfoBloc = locator<WeatherInfoBloc>();
    _geolocationBloc = locator<GeolocationBloc>()..add(LoadGeolocationEvent());
  }

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<GeolocationBloc, GeolocationState>(
      // bloc: _geolocationBloc,
      builder: (context, state) {
        if (state is GeolocationLoading) {
          return const Center(
            child: CircularProgressIndicator(),//调试卡在这里
          );
        } else if (state is GeolocationLoaded) {
          _weatherInfoBloc.add(WeatherInfoFetchEvent());
          return WeatherDisplayPage();
        }
        return Container();
      },
    );
  }

}

class WeatherDisplayPage extends StatefulWidget {
  const WeatherDisplayPage({super.key});

  @override
  State<WeatherDisplayPage> createState() => _WeatherDisplayPageState();
}

class _WeatherDisplayPageState extends State<WeatherDisplayPage> {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<WeatherInfoBloc, WeatherInfoState>(
        builder: (context, state) {
          if (state is WeatherInfoInitial || state is WeatherInfoFetchingState) {
            return _buildLoading();
          } else if (state is WeatherInfoFetchingSuccessState) {
            return _buildWeatherForcastView(context, state.weatherInfoList);
          }
          return Container();
        }
    );
  }

  Widget _buildWeatherForcastView(BuildContext context, List<WeatherInfoViewModel> weatherInfoList) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Container(alignment: Alignment.center, child: Text(weatherInfoList.first.day ?? "")),
        Text(weatherInfoList.first.weather ?? ""),
        Image.asset(weatherInfoList.first.titleImage),
        Container(alignment: Alignment.center, child: Text(weatherInfoList.first.temp ?? "")),
        Text(weatherInfoList.first.pressure.toString()),
        Text(weatherInfoList.first.wind.toString()),
        SizedBox(
            height: 100,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemBuilder: (context, index){
                return ForecastTile(
                  weatherInfoViewModel: weatherInfoList[index],
                );
              },
              itemCount: weatherInfoList.length,
            )
        )
      ],
    );
  }

  Widget _buildLoading() => const Center(child: CircularProgressIndicator());
}

依赖注入容器代码

final locator = GetIt.instance;

Future<void> initializeDependencies() async {
  locator.registerFactory(() => WeatherInfoBloc(locator()));
  locator.registerLazySingleton<WeatherInfoUseCase>(() => WeatherInfoUseCase(weatherInfoRepository: locator()));
  locator.registerLazySingleton<WeatherInfoRepository>(() => WeatherInfoRepositoryImpl(weatherInfoRemoteDataSource: locator()));
  locator.registerLazySingleton<WeatherInfoRemoteDataSource>(() => WeatherInfoRemoteDataSourceImpl(client: locator()));
  locator.registerLazySingleton<BaseClient>(() => BaseClient());
  locator.registerLazySingleton(() => http.Client());
  locator.registerFactory(() => GeolocationBloc(locator()));
  locator.registerLazySingleton<GeolocationRepository>(() => GeolocationRepository());
}

问题原因与解决办法

核心问题:Bloc实例不匹配

你在MultiBlocProvider中通过locator<GeolocationBloc>()创建了一个Bloc实例并注入到上下文,但在initState里又通过locator<GeolocationBloc>()获取了另一个新实例(因为你用了registerFactory,每次调用都会生成新实例)。你给这个新实例添加了事件,但BlocBuilder监听的是上下文里的那个实例,所以永远看不到状态变化,一直停留在初始的GeolocationLoading。

解决步骤:

  1. 统一Bloc实例来源:不要直接从locator获取Bloc,而是通过上下文获取MultiBlocProvider注入的实例。修改WeatherInfoPage的initState:
@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    _weatherInfoBloc = context.read<WeatherInfoBloc>();
    _geolocationBloc = context.read<GeolocationBloc>()..add(LoadGeolocationEvent());
  });
}
  1. 验证Bloc事件处理逻辑:检查GeolocationBloc的事件处理方法是否正确响应LoadGeolocationEvent,确保完成后发出GeolocationLoaded状态。示例:
class GeolocationBloc extends Bloc<GeolocationEvent, GeolocationState> {
  final GeolocationRepository repository;

  GeolocationBloc(this.repository) : super(GeolocationLoading()) {
    on<LoadGeolocationEvent>((event, emit) async {
      try {
        final location = await repository.getLocation();
        emit(GeolocationLoaded(location));
      } catch (e) {
        emit(GeolocationError(e.toString()));
      }
    });
  }
}
  1. 避免重复触发天气事件:当前代码在BlocBuilder的GeolocationLoaded分支中每次build都会添加事件,导致重复请求。改用BlocListener监听状态变化:
@override
Widget build(BuildContext context) {
  return BlocListener<GeolocationBloc, GeolocationState>(
    listener: (context, state) {
      if (state is GeolocationLoaded) {
        context.read<WeatherInfoBloc>().add(WeatherInfoFetchEvent());
      }
    },
    child: BlocBuilder<GeolocationBloc, GeolocationState>(
      builder: (context, state) {
        if (state is GeolocationLoading) {
          return const Center(child: CircularProgressIndicator());
        } else if (state is GeolocationLoaded) {
          return WeatherDisplayPage();
        }
        return Container();
      },
    ),
  );
}

内容的提问来源于stack exchange,提问作者mars_dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 23:48:19