为什么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中提供的信息。