回到页面后,即使已被显式更改,块状态也相同

问题描述 投票:1回答:1

我有一个使用CourseBloc的小部件

class CourseBloc extends Bloc<CourseEvent, CourseState> {
  final GetCoursesQuery getCoursesQuery;
  final GetSettingsQuery getSettingsQuery;
  final PullCoursesFromServerCommand pullCoursesFromServerCommand;
  final UpdateTasksToServerCommand updateTasksToServerCommand;
  final GetNetworkInfoQuery getNetworkInfoQuery;

  CourseBloc({
    @required GetCoursesQuery getCoursesQuery,
    @required GetSettingsQuery getSettingsQuery,
    @required PullCoursesFromServerCommand pullCoursesFromServerCommand,
    @required UpdateTasksToServerCommand updateTasksToServerCommand,
    @required GetNetworkInfoQuery getNetworkInfoQuery,
  })  : assert(getCoursesQuery != null),
        assert(getSettingsQuery != null),
        assert(pullCoursesFromServerCommand != null),
        assert(updateTasksToServerCommand != null),
        assert(getNetworkInfoQuery != null),
        this.getCoursesQuery = getCoursesQuery,
        this.getSettingsQuery = getSettingsQuery,
        this.pullCoursesFromServerCommand = pullCoursesFromServerCommand,
        this.updateTasksToServerCommand = updateTasksToServerCommand,
        this.getNetworkInfoQuery = getNetworkInfoQuery;

  @override
  CourseState get initialState => CourseInitialState();

  @override
  Stream<CourseState> mapEventToState(
    CourseEvent event,
  ) async* {
    if (event is CoursesReturnedFromTasksEvent) {
      yield CourseInitialState();
    } else if (event is CoursesPageLoadedEvent) {
      yield CourseLoadingState();

      final getCoursesEither = await getCoursesQuery(
        GetCoursesParams(
          truckNumber: event.truckNumber,
        ),
      );

      yield* getCoursesEither.fold((failure) async* {
        yield CourseFetchedStateFailureState(error: "coursesDatabaseError");
      }, (result) async* {
        if (result != null) {
          final getSettingsEither = await getSettingsQuery(NoQueryParams());

          yield* getSettingsEither.fold((failure) async* {
            yield CourseFetchedStateFailureState(error: "coursesDatabaseError");
          }, (settingsResult) async* {
            if (result != null) {
              final networkInfoEither =
                  await this.getNetworkInfoQuery(NoQueryParams());

              yield* networkInfoEither.fold((failure) async* {
                yield CourseErrorState();
              }, (success) async* {
                yield CourseFetchedState(
                  settings: settingsResult,
                  courses: result,
                  isThereInternet: success,
                );
              });
            } else {
              yield CourseFetchedStateFailureState(
                  error: "coursesFetchFromDatabaseError");
            }
          });
        } else {
          yield CourseFetchedStateFailureState(
              error: "coursesFetchFromDatabaseError");
        }
      });
    } else if (event is CoursesRefreshButtonPressedEvent) {
      yield CourseLoadingState();

      final networkInfoEither = await this.getNetworkInfoQuery(NoQueryParams());

      yield* networkInfoEither.fold((failure) async* {
        yield CourseErrorState();
      }, (success) async* {
        if (success) {
          final updateTasksToServerEither = await updateTasksToServerCommand(
              UpdateTasksParams(truckNumber: event.truckNumber));

          yield* updateTasksToServerEither.fold((failure) async* {
            yield CourseFetchedStateFailureState(error: "coursesDatabaseError");
          }, (result) async* {
            final pullCoursesFromServerEither =
                await pullCoursesFromServerCommand(
                    PullCoursesParams(truckNumber: event.truckNumber));

            yield* pullCoursesFromServerEither.fold((failure) async* {
              yield CourseFetchedStateFailureState(
                  error: "coursesDatabaseError");
            }, (result) async* {
              if (result != null) {
                yield CoursePulledFromServerState();
              } else {
                yield CourseFetchedStateFailureState(
                    error: "coursesFetchFromDatabaseError");
              }
            });
          });
        } else {
          yield CourseNoInternetState();
        }
      });
    } else if (event is CoursesRefreshFromTasksButtonPressedEvent) {
      serviceLocator<TaskBloc>().add(
        TasksLoadingEvent(),
      );

      final networkInfoEither = await this.getNetworkInfoQuery(NoQueryParams());

      yield* networkInfoEither.fold((failure) async* {
        serviceLocator<TaskBloc>().add(
          TasksReloadingErrorEvent(),
        );
      }, (success) async* {
        if (success) {
          final updateTasksToServerEither = await updateTasksToServerCommand(
              UpdateTasksParams(truckNumber: event.truckNumber));

          yield* updateTasksToServerEither.fold((failure) async* {
            yield CourseFetchedStateFailureState(error: "coursesDatabaseError");
          }, (result) async* {
            final pullCoursesFromServerEither =
                await pullCoursesFromServerCommand(
                    PullCoursesParams(truckNumber: event.truckNumber));

            yield* pullCoursesFromServerEither.fold((failure) async* {
              serviceLocator<TaskBloc>().add(
                TasksFetchedFailureEvent(failure: "coursesDatabaseError"),
              );
            }, (result) async* {
              if (result != null) {
                serviceLocator<TaskBloc>().add(
                  TasksPulledFromServerEvent(
                    truckNumber: event.truckNumber,
                    courseNumber: event.courseNumber,
                    courseId: event.courseId,
                  ),
                );
              } else {
                serviceLocator<TaskBloc>().add(
                  TasksFetchedFailureEvent(
                      failure: "coursesFetchFromDatabaseError"),
                );
              }
            });
          });
        } else {
          yield CourseNoInternetState();
        }
      });
    }
  }
}

我在小部件页面中如下使用BlocBuilderBlocListener

BlocBuilder<CourseBloc, CourseState>(
   builder: (context, state) {
     if (state is CourseFetchedState) {
     // here I have logic if the course is fetched
   }
...
),

BlocListener<CourseBloc, CourseState>(
   listener: (context, state) {
     if (state is CourseNoInternetState) {
     ...
   }
...
),

[有时,我正在离开此小部件。然后,我想回到第一个(课程)窗口小部件。我会:

serviceLocator<CourseBloc>().add(
     CoursesReturnedFromTasksEvent(),
);

serviceLocator.resetLazySingleton<TaskBloc>(
     instance: serviceLocator<TaskBloc>(),
);

Navigator.of(context).pop(true);

这告诉CourseBloc期望CoursesReturnedFromTasksEvent(),重置新的TaskBloc(因为我不再在此页面上,并且我不需要知道它处于什么状态)并弹出当前上下文。

然后我被导航回去。 CourseBloc的映射方法适用于新状态,并根据'if'产生:

if (event is CoursesReturnedFromTasksEvent) {
  yield CourseInitialState();
}

但是“课程”页面中的构建器处于先前状态。 CourseFetchedState。而且它还没有“采用”新状态(初始状态)。

任何可能会发生这种情况的想法?

这里是州:

abstract class CourseState {
  CourseState();
}

class CourseInitialState extends CourseState {}

class CourseReturnedFromTasksState extends CourseState {}

class CourseLoadingState extends CourseState {}

class CourseErrorState extends CourseState {}

class CourseNoInternetState extends CourseState {}

class CoursePulledFromServerState extends CourseState {}

class CourseFetchedState extends CourseState {
  final SettingsAggregate settings;
  final List<CourseAggregate> courses;
  final bool isThereInternet;

  CourseFetchedState({
    @required this.settings,
    @required this.courses,
    @required this.isThereInternet,
  });
}

class CourseFetchedStateFailureState extends CourseState {
  final String error;

  CourseFetchedStateFailureState({@required this.error});
}

和事件:

abstract class CourseEvent {
  CourseEvent();
}

class CoursesRefreshButtonPressedEvent extends CourseEvent {
  final String truckNumber;

  CoursesRefreshButtonPressedEvent({@required this.truckNumber});
}

class CoursesRefreshFromTasksButtonPressedEvent extends CourseEvent {
  final String courseNumber;
  final String truckNumber;
  final int courseId;

  CoursesRefreshFromTasksButtonPressedEvent({
    @required this.courseNumber,
    @required this.truckNumber,
    @required this.courseId,
  });
}

class CoursesReturnedFromTasksEvent extends CourseEvent {}

class CoursesPageLoadedEvent extends CourseEvent {
  final String truckNumber;

  CoursesPageLoadedEvent({
    this.truckNumber,
  });
}

编辑这是提供Bloc的方式:

Column buildBody(BuildContext context) {
    return Column(
      children: <Widget>[
        BlocProvider(
          create: (_) => serviceLocator<CourseBloc>(),
          child: BlocBuilder<CourseBloc, CourseState>(
            builder: (context, state) {
              if (state is CourseFetchedState) {
              ...
              }
            ...
            }
           ),
          ),
         ],
        );
       }

serviceLocator()在应用启动时仅实例化一次。它注册了整个应用程序生命周期中所需的所有实例,以实现依赖关系注入。这是CourseBloc注册:

import 'package:get_it/get_it.dart';

final serviceLocator = GetIt.instance;
...
serviceLocator.registerLazySingleton(
    () => CourseBloc(
      getCoursesQuery: serviceLocator(),
      getSettingsQuery: serviceLocator(),
      pullCoursesFromServerCommand: serviceLocator(),
      updateTasksToServerCommand: serviceLocator(),
      getNetworkInfoQuery: serviceLocator(),
    ),
  );
...
flutter flutter-bloc
1个回答
0
投票

我对GetIt并不是很熟悉,但是据我所知:

  1. 您用CourseBloc制作了serviceLocator的单例。
  2. 您使用BlocProvider将该单例提供给相关上下文(导致CourseBloc的2个实例)。
  3. 您的BlocBuilder使用通过BlocProvider提供的实例,因为您没有通过bloc参数明确地告诉它(它将在相同上下文中查找小部件树以找到CourseBloc)。
  4. 您使用由CourseBloc制成的serviceLocator的实例添加CoursesReturnedFromTasksEvent()

您可以尝试通过BlocBuilder参数为bloc显式指定bloc实例,因此它不会通过上下文自动搜索CourseBloc。如果可行,则可以删除BlocProvider,但事实是,通过这种方式,您需要手动处理CourseBloc

BlocBuilder<CourseBloc, CourseState>(
  bloc: serviceLocator<CourseBloc>(), // <=() This is the additional line
  builder: (context, state) {
    if (state is CourseFetchedState) {
    // here I have logic if the course is fetched
    }
    ...
  }
)

或者您可以按常规方式添加事件,但是您仍然需要手动处理由CourseBloc制作的serviceLocator单身人士>

BlocProvider.of<CourseBloc>(context).add(
  CoursesReturnedFromTasksEvent(),
);
© www.soinside.com 2019 - 2024. All rights reserved.