BlocProvider.of () вызывается с контекстом, который не содержит Blo c типа TrackingBloc - PullRequest
0 голосов
/ 07 марта 2020

Я пытаюсь предоставить TrackingBloc в MapScreen, но при отправке события из onPressed я получаю сообщение об ошибке BlocProvider.of() called with a context that does not contain a Bloc of type TrackingBloc. MapScreen также использует MapBloc, предоставленное main(), но для TrackingBloc Я хочу сделать это локальным, чтобы не загромождать MultiBlocProvider в main(). Я попытался:

  1. Использовать параметр bloc: в BlocListener<TrackingBloc, TrackingState>, как мне сказали, что он просто обеспечивает blo c, как BlocProvider ( https://github.com/felangel/bloc/issues/930#issuecomment -593790702 ) но это не сработало.
  2. Затем я попытался сделать MultiBlocLister дочерним по отношению к MultiBlocProvider и установить TrackingBloc, но все равно получить сообщение.
  3. Установите TrackingBloc в MultiBlocProvider в `main () и работайте как положено.

Почему 1 и 2 не предоставляют TrackingBloc дереву? Большое спасибо за вашу помощь.

MapScreen:

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(

main ():

  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:

Ответы [ 2 ]

1 голос
/ 07 марта 2020

Справа, я вижу, что с вашим кодом две вещи не так.

Первый: Вы предоставляете несколько TrackingBlo c, в основном и MapScreen.

Второй: Вы получаете доступ к TrackingBlo c через BlocListener в том же контексте, в котором вы его предоставляете (второй BlocProvider(create: (context) {return TrackingBloc();})). Я предполагаю, что именно это и вызывает ошибку.

BlocProvider.of () вызывается с контекстом, который не содержит Blo c типа TrackingBlo c

Я думаю, что простое удаление BlocProvider в MapScreen сделает эту работу.

0 голосов
/ 07 марта 2020

Я предоставлял TrackingBloc из неправильного места в дереве виджетов. Я могу предоставить blo c глобально, в котором я не нуждаюсь, поэтому, чтобы предоставить его локально, как я хочу, я должен предоставить его из Blocbuilder в 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 и BlocListener 'bloc: свойства теста. Приветствия.

...