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
我想把它放在本地,而不是让 MultiBlocProvider
在 main()
中混乱。
我试过了:
- 要在
BlocListener<TrackingBloc, TrackingState>
中使用 bloc:
参数,因为有人告诉我它只是提供 bloc 作为 BlocProvider
会 (https://github.com/felangel/bloc/issues/930#issuecomment-593790702) 但没用。
- 然后我尝试将
MultiBlocLister
变成 MultiBlocProvider
的 child 并在那里设置 TrackingBloc
,但仍然收到消息。
- 在 `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
从小部件树中的错误位置提供。
我可以在全球范围内提供我不需要的集团,所以要根据需要在本地提供它,我必须从 Blocbuilder
in 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:
属性的面团..
干杯。
我正在尝试向 MapScreen
提供 TrackingBloc
,但是当从 onPressed
发送事件时,我收到错误 BlocProvider.of() called with a context that does not contain a Bloc of type TrackingBloc.
MapScreen
也使用了 main()
提供的 MapBloc
,但是对于 TrackingBloc
我想把它放在本地,而不是让 MultiBlocProvider
在 main()
中混乱。
我试过了:
- 要在
BlocListener<TrackingBloc, TrackingState>
中使用bloc:
参数,因为有人告诉我它只是提供 bloc 作为BlocProvider
会 (https://github.com/felangel/bloc/issues/930#issuecomment-593790702) 但没用。 - 然后我尝试将
MultiBlocLister
变成MultiBlocProvider
的 child 并在那里设置TrackingBloc
,但仍然收到消息。 - 在 `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
从小部件树中的错误位置提供。
我可以在全球范围内提供我不需要的集团,所以要根据需要在本地提供它,我必须从 Blocbuilder
in 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:
属性的面团..
干杯。