BlocProvider.of() 使用不包含 TrackingBloc 类型的 Bloc 的上下文调用

BlocProvider.of() called with a context that does not contain a Bloc of type TrackingBloc

我正在尝试向 MapScreen 提供 TrackingBloc,但是当从 onPressed 发送事件时,我收到错误 BlocProvider.of() called with a context that does not contain a Bloc of type TrackingBloc. MapScreen 也使用了 main() 提供的 MapBloc,但是对于 TrackingBloc 我想把它放在本地,而不是让 MultiBlocProvidermain() 中混乱。 我试过了:

  1. 要在 BlocListener<TrackingBloc, TrackingState> 中使用 bloc: 参数,因为有人告诉我它只是提供 bloc 作为 BlocProvider 会 (https://github.com/felangel/bloc/issues/930#issuecomment-593790702) 但没用。
  2. 然后我尝试将 MultiBlocLister 变成 MultiBlocProvider 的 child 并在那里设置 TrackingBloc,但仍然收到消息。
  3. 在 `main() 的 MultiBlocProvider 中设置 TrackingBloc 并按预期工作。

为什么 1 和 2 不向树提供 TrackingBloc? 非常感谢您的帮助。

地图屏幕:

class MapScreen extends StatefulWidget {
  final String name;
  final MapRepository _mapRepository;

  MapScreen(
      {Key key, @required this.name, @required MapRepository mapRepository})
      : assert(mapRepository != null),
        _mapRepository = mapRepository,
        super(key: key);

  @override
  _MapScreenState createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  List<Marker> alerts;
  LatLng userLocation;

  MapController _mapController = MapController();

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<TrackingBloc>(create: (context) {
          return TrackingBloc();
        }),
      ],
      child: MultiBlocListener(
        listeners: [
          BlocListener<MapBloc, MapState>(
              listener: (BuildContext context, MapState state) {
            if (state is LocationStream) {
              setState(() {
                userLocation = (state).location;
//              print(
//                  ' @@@@ MapBloc actual user location from stream  is : $userLocation');
              });
            }
            if (state is MapCenter) {
              userLocation = (state).location;
//            print(' @@@@ MapBloc initial center location is : $userLocation');
              _mapController.move(userLocation, 16);
            }
          }),
          BlocListener<TrackingBloc, TrackingState>(
//              bloc: TrackingBloc(),
              listener: (BuildContext context, TrackingState state) {
            if (state is TrackedRoute) {
              List<Position> route = (state).trackedRoute;
              print(route);
            }
          }),
        ],
        child: Scaffold(

主要():

  runApp(
    MultiBlocProvider(
      providers: [
        BlocProvider<AuthenticationBloc>(
          create: (context) {
            return AuthenticationBloc(
              userRepository: UserRepository(),
            )..add(AppStarted());
          },
        ),
        BlocProvider<MapBloc>(create: (context) {
          return MapBloc(
            mapRepository: mapRepository,
          )
            ..add(GetLocationStream())
            ..add(GetLocation());
        }),
        BlocProvider<TrackingBloc>(create: (context) {
          return TrackingBloc();
        }),
//        BlocProvider<AlertBloc>(create: (context) {
//          return AlertBloc(
//            alertRepository: alertRepository,
//          )..add(LoadAlerts());
//        }),
      ],
      child:

正确的,我可以看出您的代码有两处错误。

首先:你在main和MapScreen中提供了多个TrackingBloc。

第二个: 您正在通过 BlocListener 在您提供它的同一上下文中访问 TrackingBloc(第二个 BlocProvider(create: (context) {return TrackingBloc();}))。我猜这是导致错误的原因。

BlocProvider.of() called with a context that does not contain a Bloc of type TrackingBloc

我认为只需删除 MapScreen 中的 BlocProvider 即可。

TrackingBloc 从小部件树中的错误位置提供。 我可以在全球范围内提供我不需要的集团,所以要根据需要在本地提供它,我必须从 Blocbuilderin main() 提供它,它返回 MapScreen.

更改 main() 来自:

    return MaterialApp(
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (context, state) {
          if (state is Unauthenticated) {
            return LoginScreen(userRepository: _userRepository);
          }
          if (state is Authenticated) {
//            BlocProvider.of<MapBloc>(context).add(GetLocationStream());
//            BlocProvider.of<AlertBloc>(context).add(LoadAlerts());
            return MapScreen(
              mapRepository: _mapRepository,
              name: state.displayName,
//              alertRepository: FirebaseAlertRepository(),
            );
          }
          if (state is Unauthenticated) {
            return LoginScreen(userRepository: _userRepository);
          }
          return SplashScreen();
        },
      ),
    );

至:

return MaterialApp(
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (context, state) {
          if (state is Unauthenticated) {
            return LoginScreen(userRepository: _userRepository);
          }
          if (state is Authenticated) {
//            BlocProvider.of<MapBloc>(context).add(GetLocationStream());
//            BlocProvider.of<AlertBloc>(context).add(LoadAlerts());
            return MultiBlocProvider(
              providers: [
                BlocProvider<TrackingBloc>(create: (context) {
                  return TrackingBloc();
                }),
              ],
              child: MapScreen(
                mapRepository: _mapRepository,
                name: state.displayName,
//              alertRepository: FirebaseAlertRepository(),
              ),
            );
            return MapScreen(
              mapRepository: _mapRepository,
              name: state.displayName,
//              alertRepository: FirebaseAlertRepository(),
            );
          }
          if (state is Unauthenticated) {
            return LoginScreen(userRepository: _userRepository);
          }
          return SplashScreen();
        },
      ),
    );

使它按我的预期工作。 然后在 MapScreen 中,我只是使用不同的 BlocListener 来收听全局的 MapBloc 或本地的 TrackingBloc :

class _MapScreenState extends State<MapScreen> {
  List<Marker> alerts;
  LatLng userLocation;

  MapController _mapController = MapController();

  @override
  Widget build(BuildContext context) {
    return MultiBlocListener(
      listeners: [
        BlocListener<MapBloc, MapState>(
            listener: (BuildContext context, MapState state) {
          if (state is LocationStream) {
            setState(() {
              userLocation = (state).location;
//              print(
//                  ' @@@@ MapBloc actual user location from stream  is : $userLocation');
            });
          }
          if (state is MapCenter) {
            userLocation = (state).location;
//            print(' @@@@ MapBloc initial center location is : $userLocation');
            _mapController.move(userLocation, 16);
          }
        }),
        BlocListener<TrackingBloc, TrackingState>(
//              bloc: TrackingBloc(),
            listener: (BuildContext context, TrackingState state) {
//      userLocation = (state as LocationStream).location;
          if (state is TrackedRoute) {
            List<Position> route = (state).trackedRoute;
            print(route);
//            initialLocation = (state).location.then((value) {
//              print('@@@@@@ value is : $value');
////              _mapController.move(value, 16.0);
//              return value;
//            }
//            );
          }
        }),
      ],
      child: Scaffold(

希望这会帮助其他刚开始使用 flutter_bloc 的人,他们可能找不到足够清楚的小部件文档使用说明。 还是要充分了解BlocProvider的和BlocListenerbloc:属性的面团.. 干杯。