返回页面后 bloc 状态是相同的,即使它已被显式更改
bloc state is the same after coming back to a page even though it was explicitly changed
我有一个使用 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();
}
});
}
}
}
我在widget页面使用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。而且它还没有 'taken' 新状态(初始)。
知道为什么会发生这种情况吗?
以下是美国:
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(),
),
);
...
我不是很熟悉GetIt
,但据我所知:
- 你用
serviceLocator
创建了 CourseBloc
的单例。
- 您使用
BlocProvider
将该单例提供给相关上下文(导致 CourseBloc
的 2 个实例)。
- 您的
BlocBuilder
使用通过 BlocProvider
提供的实例,因为您没有通过 bloc
参数明确告知(它将查找小部件树以找到 CourseBloc
在相同的上下文中)。
- 您使用
serviceLocator
制作的 CourseBloc
的实例来添加 CoursesReturnedFromTasksEvent()
。
尝试通过 BlocProvider.of
以常规方式添加事件,但您仍然需要手动处理 serviceLocator
制作的 CourseBloc
单例
BlocProvider.of<CourseBloc>(context).add(
CoursesReturnedFromTasksEvent(),
);
我有一个使用 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();
}
});
}
}
}
我在widget页面使用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。而且它还没有 'taken' 新状态(初始)。
知道为什么会发生这种情况吗?
以下是美国:
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(),
),
);
...
我不是很熟悉GetIt
,但据我所知:
- 你用
serviceLocator
创建了CourseBloc
的单例。 - 您使用
BlocProvider
将该单例提供给相关上下文(导致CourseBloc
的 2 个实例)。 - 您的
BlocBuilder
使用通过BlocProvider
提供的实例,因为您没有通过bloc
参数明确告知(它将查找小部件树以找到CourseBloc
在相同的上下文中)。 - 您使用
serviceLocator
制作的CourseBloc
的实例来添加CoursesReturnedFromTasksEvent()
。
尝试通过 BlocProvider.of
以常规方式添加事件,但您仍然需要手动处理 serviceLocator
CourseBloc
单例
BlocProvider.of<CourseBloc>(context).add(
CoursesReturnedFromTasksEvent(),
);