为什么BlocBuilder在使用get_it时卡在初始状态?
Why BlocBuilder is stuck in the initial state while using get_it?
我正在使用 flutter_bloc to manage the states of my app, and get_it to inject the needed dependencies following the idea suggested by the Reso Coder's Flutter Clean Architecture Proposal。
一切正常,除了 bloc 没有改变它的状态(它停留在初始状态)
这里是涉及到的代码类:
美国
abstract class PaintingsState extends Equatable {
final properties = const <dynamic>[];
PaintingsState([properties]);
@override
List<Object> get props => [properties];
}
class PaintingsLoading extends PaintingsState {}
class PaintingsLoaded extends PaintingsState {
final PaintingCardItems cardItems;
PaintingsLoaded({@required this.cardItems}) : super([cardItems]);
}
class Error extends PaintingsState {
final String message;
Error({@required this.message}) : super([message]);
}
事件
abstract class PaintingsEvent extends Equatable {
const PaintingsEvent();
@override
List<Object> get props => [];
}
/// Tells the bloc that it needs to load the paintings from the PaintingsRepository
class GetPaintings extends PaintingsEvent {}
集团
const String FILE_NOT_FOUND_MESSAGE = 'FileNotFound Failure';
class PaintingsBloc extends Bloc<PaintingsEvent, PaintingsState> {
final GetPaintingCardItems getCardItems;
PaintingsBloc({@required this.getCardItems}) : super(PaintingsLoading());
@override
Stream<PaintingsState> mapEventToState(PaintingsEvent event) async* {
if (event is GetPaintings) {
yield* _mapGetPaintingsToState();
}
}
Stream<PaintingsState> _mapGetPaintingsToState() async* {
yield PaintingsLoading();
final failureOrPaintingCardItems = await getCardItems(NoParams());
yield failureOrPaintingCardItems.fold(
(failure) => Error(message: _mapFailureToMessage(failure)),
(paintingCardItems) => PaintingsLoaded(cardItems: paintingCardItems));
}
String _mapFailureToMessage(Failure failure) {
switch (failure.runtimeType) {
case FileNotFound:
return FILE_NOT_FOUND_MESSAGE;
default:
return 'Unexpected error';
}
}
}
依赖注入
/// Ambient variable to access the service locator
final sl = GetIt.instance;
/// Set up all the objects you want to access later through the service locator [sl]
void setUpServiceLocator() {
initFeatures();
}
void initFeatures() {
//! Features - Paintings
// Bloc
sl.registerLazySingleton<PaintingsBloc>(() => PaintingsBloc(getCardItems: sl<GetPaintingCardItems>()));
// Use cases
sl.registerLazySingleton<GetPaintingCardItems>(() => GetPaintingCardItems(sl<PaintingsRepository>()));
// Repository
sl.registerLazySingleton<PaintingsRepository>(
() => PaintingsRepositoryImpl(dataSource: sl<PaintingsDataSource>()));
// Data sources
sl.registerLazySingleton<PaintingsDataSource>(() => PaintingsDataSourceImpl());
}
main.dart
void main() {
// dependencies injection
setUpServiceLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<PaintingsBloc>(
create: (_) => sl<PaintingsBloc>(),
child: MaterialApp(
title: 'My Paintings',
theme: appTheme,
initialRoute: '/',
onGenerateRoute: RouteGenerator.generateRoute,
),
);
}
}
我使用 BlocBuilder 的页面
class PaintingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
...
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Stack(
children: <Widget>[
SafeArea(
child: Column(
...
BlocBuilder<PaintingsBloc, PaintingsState>(
builder: (context, state) {
if(state is PaintingsLoading) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
} else if(state is PaintingsLoaded) {
List<PaintingCardItem> _list = state.cardItems.paintingCardItems;
return Expanded(
child: SizedBox(
child: _list.length != 0
? ListCardView(
cardItems: _list)
: Container(
child: Center(child: Text('Empty list'))),
),
);
} else if(state is Error){
return Container(
child: Center(child: Text(state.message)));
} else {
return Container(
child: Center(child: Text('Unknown Error')));
}
}
)
],
))
],
),
),
);
}
}
因此,不知何故,集团的状态不会从 PaintingsLoading 更改为 PaintingsLoaded 或 Error。
如果有人能给我一些解决这个问题的想法,我将不胜感激。
我解决了,我只需要将事件添加到集团即可。所以,我的解决方案是创建另一个名为 PaintingsInitialState 的状态,如下所示:
美国
...
class PaintingsInitialState extends PaintingsState {}
...
然后在Bloc中,我只是更改了bloc的构造函数。
PaintingsBloc({@required this.getCardItems}) : super(PaintingsInitialState());`
最后,我在 BlocBuilder 的 builder 参数中添加了以下条件。
if (state is PaintingsInitialState) {
_paintingsBloc.add(GetPaintings());
}
我认为offitial site of the bloc library can be useful to understand how to use bloc pattern and libraries properly - particularly Flutter Wheather Tutorial中提供的信息。
我正在使用 flutter_bloc to manage the states of my app, and get_it to inject the needed dependencies following the idea suggested by the Reso Coder's Flutter Clean Architecture Proposal。
一切正常,除了 bloc 没有改变它的状态(它停留在初始状态)
这里是涉及到的代码类:
美国
abstract class PaintingsState extends Equatable {
final properties = const <dynamic>[];
PaintingsState([properties]);
@override
List<Object> get props => [properties];
}
class PaintingsLoading extends PaintingsState {}
class PaintingsLoaded extends PaintingsState {
final PaintingCardItems cardItems;
PaintingsLoaded({@required this.cardItems}) : super([cardItems]);
}
class Error extends PaintingsState {
final String message;
Error({@required this.message}) : super([message]);
}
事件
abstract class PaintingsEvent extends Equatable {
const PaintingsEvent();
@override
List<Object> get props => [];
}
/// Tells the bloc that it needs to load the paintings from the PaintingsRepository
class GetPaintings extends PaintingsEvent {}
集团
const String FILE_NOT_FOUND_MESSAGE = 'FileNotFound Failure';
class PaintingsBloc extends Bloc<PaintingsEvent, PaintingsState> {
final GetPaintingCardItems getCardItems;
PaintingsBloc({@required this.getCardItems}) : super(PaintingsLoading());
@override
Stream<PaintingsState> mapEventToState(PaintingsEvent event) async* {
if (event is GetPaintings) {
yield* _mapGetPaintingsToState();
}
}
Stream<PaintingsState> _mapGetPaintingsToState() async* {
yield PaintingsLoading();
final failureOrPaintingCardItems = await getCardItems(NoParams());
yield failureOrPaintingCardItems.fold(
(failure) => Error(message: _mapFailureToMessage(failure)),
(paintingCardItems) => PaintingsLoaded(cardItems: paintingCardItems));
}
String _mapFailureToMessage(Failure failure) {
switch (failure.runtimeType) {
case FileNotFound:
return FILE_NOT_FOUND_MESSAGE;
default:
return 'Unexpected error';
}
}
}
依赖注入
/// Ambient variable to access the service locator
final sl = GetIt.instance;
/// Set up all the objects you want to access later through the service locator [sl]
void setUpServiceLocator() {
initFeatures();
}
void initFeatures() {
//! Features - Paintings
// Bloc
sl.registerLazySingleton<PaintingsBloc>(() => PaintingsBloc(getCardItems: sl<GetPaintingCardItems>()));
// Use cases
sl.registerLazySingleton<GetPaintingCardItems>(() => GetPaintingCardItems(sl<PaintingsRepository>()));
// Repository
sl.registerLazySingleton<PaintingsRepository>(
() => PaintingsRepositoryImpl(dataSource: sl<PaintingsDataSource>()));
// Data sources
sl.registerLazySingleton<PaintingsDataSource>(() => PaintingsDataSourceImpl());
}
main.dart
void main() {
// dependencies injection
setUpServiceLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<PaintingsBloc>(
create: (_) => sl<PaintingsBloc>(),
child: MaterialApp(
title: 'My Paintings',
theme: appTheme,
initialRoute: '/',
onGenerateRoute: RouteGenerator.generateRoute,
),
);
}
}
我使用 BlocBuilder 的页面
class PaintingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
...
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Stack(
children: <Widget>[
SafeArea(
child: Column(
...
BlocBuilder<PaintingsBloc, PaintingsState>(
builder: (context, state) {
if(state is PaintingsLoading) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
} else if(state is PaintingsLoaded) {
List<PaintingCardItem> _list = state.cardItems.paintingCardItems;
return Expanded(
child: SizedBox(
child: _list.length != 0
? ListCardView(
cardItems: _list)
: Container(
child: Center(child: Text('Empty list'))),
),
);
} else if(state is Error){
return Container(
child: Center(child: Text(state.message)));
} else {
return Container(
child: Center(child: Text('Unknown Error')));
}
}
)
],
))
],
),
),
);
}
}
因此,不知何故,集团的状态不会从 PaintingsLoading 更改为 PaintingsLoaded 或 Error。
如果有人能给我一些解决这个问题的想法,我将不胜感激。
我解决了,我只需要将事件添加到集团即可。所以,我的解决方案是创建另一个名为 PaintingsInitialState 的状态,如下所示:
美国
...
class PaintingsInitialState extends PaintingsState {}
...
然后在Bloc中,我只是更改了bloc的构造函数。
PaintingsBloc({@required this.getCardItems}) : super(PaintingsInitialState());`
最后,我在 BlocBuilder 的 builder 参数中添加了以下条件。
if (state is PaintingsInitialState) {
_paintingsBloc.add(GetPaintings());
}
我认为offitial site of the bloc library can be useful to understand how to use bloc pattern and libraries properly - particularly Flutter Wheather Tutorial中提供的信息。