我有一个使用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();
}
});
}
}
}
我在小部件页面中按如下方式使用BlocBuilder
和BlocListener
:
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(),
),
);
...
答案 0 :(得分:1)
我对GetIt
并不是很熟悉,但是据我所知:
CourseBloc
与serviceLocator
做成单例。BlocProvider
将该单例提供给相关上下文(导致CourseBloc
的2个实例)。BlocBuilder
使用通过BlocProvider
提供的实例,因为您没有通过bloc
参数明确地告诉它(它将在窗口小部件树中查找CourseBloc
相同的上下文)。CourseBloc
制作的serviceLocator
实例添加CoursesReturnedFromTasksEvent()
。尝试通过BlocProvider.of
来添加事件,但是您仍然需要手动处理CourseBloc
制作的serviceLocator
单例
BlocProvider.of<CourseBloc>(context).add(
CoursesReturnedFromTasksEvent(),
);