英文:
Flutter BLoC 8.0.0. not emiting new state properly
问题
我已经为您翻译了代码部分,以下是翻译好的内容:
我在Flutter中创建了一个处理UI事件的BLoC(8.0.0)。我有一个ToggleButtons小部件,用户可以在三个按钮之间切换,当前选中的按钮将从数据库返回一组实体,然后在屏幕上显示这些实体。这些实体具有`bool isSale`和`bool isClosed`等其他参数,按下每个按钮应告诉BLoC搜索数据库以查找具有不同这些布尔值组合的实体,即:
1 - isSale = true,isClosed = false
2 - isSale = true,isClosed = true
3 - isSale = false,isClosed = false
我认为错误一定在我即将发布的代码中。
我创建了如下的状态:
```dart
abstract class DocViewerState extends Equatable {
const DocViewerState();
}
class DocViewerLoadingState extends DocViewerState {
@override
List<Object> get props => [];
}
class DocViewerLoadedState extends DocViewerState {
bool isSale;
bool isClosed;
int? selectedIndex;
DocViewerLoadedState({required this.isSale, required this.isClosed, required this.selectedIndex});
@override
List<Object> get props => [isSale, isClosed];
}
用于触发此功能的事件如下:
abstract class DocViewerEvent extends Equatable {
const DocViewerEvent();
}
class ModeChangedEvent extends DocViewerEvent {
bool isSale;
bool isClosed;
ModeChangedEvent({required this.isSale, required this.isClosed});
@override
List<Object?> get props => [isSale, isClosed];
}
我已设置一个事件处理程序来更改搜索模式,其函数如下:
void _onModeChanged(ModeChangedEvent event, Emitter<DocViewerState> emit) {
emit(DocViewerLoadingState());
this.isSale = event.isSale;
this.isClosed = event.isClosed; // 这里是因为函数外部的搜索流
try {
emit(DocViewerLoadedState(
isClosed: event.isClosed,
isSale: event.isSale,
selectedIndex: null,
)); // 这个发射只适用于第一和第三种组合
} catch (e) {
print(e); /// 我尝试把这个放在这里,因为我以为可能有一些悄无声息的异常。
/// 没有异常。
}
print(event.isSale); // 这些用于打印结果,下面有描述。
print(event.isClosed);
print(state);
}
我再次检查了我是否在状态和事件中使用了Equatable。我还尝试设置了上面的try catch代码。以下是在发射后的打印结果:
第一种组合 (
I/flutter (5019): true
I/flutter (5019): false
I/flutter (5019): DocViewerLoadedState(true, false)
第二种组合
I/flutter (5019): true
I/flutter (5019): true
I/flutter (5019): DocViewerLoadingState()
第三种组合
I/flutter (5019): false
I/flutter (5019): false
I/flutter (5019): DocViewerLoadedState(false, false)
如您所见,新状态没有更新,尽管参数传递正确。我应该怎么做才能使它按预期工作?
英文:
I have created a BLoC (8.0.0) in Flutter that handles events in the UI. I have a ToggleButtons widget where the user toggles between three buttons and whichever one is currently selected, returns a list of entities from the database which are then displayed on the screen. These are entities that have, among other parameters, the bool isSale
and bool isClosed
, and pressing each of the buttons should tell BLoC to search the database for entities with a different combination of these booleans, namely:
1 - isSale = true, isClosed = false
2 - isSale = true, isClosed = true
3 - isSale = false, isClosed = false
I think the error must be somewhere in the code I'm going to post.
I have created states as follows:
abstract class DocViewerState extends Equatable {
const DocViewerState();
}
class DocViewerLoadingState extends DocViewerState {
@override
List<Object> get props => [];
}
class DocViewerLoadedState extends DocViewerState {
bool isSale;
bool isClosed;
int? selectedIndex;
DocViewerLoadedState({required this.isSale, required this.isClosed, required this.selectedIndex});
@override
List<Object> get props => [isSale, isClosed];
}
The event I use to trigger this function looks like this:
abstract class DocViewerEvent extends Equatable {
const DocViewerEvent();
}
class ModeChangedEvent extends DocViewerEvent {
bool isSale;
bool isClosed;
ModeChangedEvent({required this.isSale, required this.isClosed});
@override
List<Object?> get props => [isSale, isClosed];
}
I have set up an event handler to change the search mode, the function of which looks like this:
void _onModeChanged(ModeChangedEvent event, Emitter<DocViewerState> emit) {
emit(DocViewerLoadingState());
this.isSale = event.isSale;
this.isClosed = event.isClosed; // This is here because of the search stream outside of this function
try {
emit(DocViewerLoadedState(
isClosed: event.isClosed,
isSale: event.isSale,
selectedIndex: null,
)); // This emit works only for the first and third combination
} catch (e) {
print(e); /// I tried to put this here because I thought maybe there is some silent exception.
/// There is none.
}
print(event.isSale); // These are for printing the results, they are described below.
print(event.isClosed);
print(state);
}
I double checked that I'm using Equatable for the states and event. I also tried setting up the try catch code that is above. These are results of prints below emitting:
1st combination (
I/flutter ( 5019): true
I/flutter ( 5019): false
I/flutter ( 5019): DocViewerLoadedState(true, false)
2nd combination
I/flutter ( 5019): true
I/flutter ( 5019): true
I/flutter ( 5019): DocViewerLoadingState()
3rd combination
I/flutter ( 5019): false
I/flutter ( 5019): false
I/flutter ( 5019): DocViewerLoadedState(false, false)
As you can see, the new state isn't updating although the parameters are passed correctly. What can I do to make it work as it should?
答案1
得分: 1
我找到了解决方案。由于某种原因,参数 isClosed 似乎是某种关键字。将上面所有出现的 isClosed 重命名为 closed 突然使发射工作正常。
英文:
I found the solution. For some reason, parameter isClosed seems to be some kind of keyword. Renaming isClosed to closed in all instances where it's used above suddenly made the emiting work.
答案2
得分: 0
这只是一个非常猜测的想法,但可能是竞态条件。您可以将方法设为async
,然后在打印状态之前添加延迟。
另外,我通常使用Bloc Observer来监视状态变化:
class _DebugBlocObserver extends BlocObserver {
@override
void onChange(BlocBase<dynamic> bloc, Change<dynamic> change) {
super.onChange(bloc, change);
log('onChange(${bloc.runtimeType}, $change)');
}
@override
void onError(BlocBase<dynamic> bloc, Object error, StackTrace stackTrace) {
log('onError(${bloc.runtimeType}, $error, $stackTrace)');
super.onError(bloc, error, stackTrace);
}
}
然后,在启动应用程序时注册此观察者:
Bloc.observer = _DebugBlocObserver();
这将打印出所有状态变化。详细文档请参考:https://bloclibrary.dev/#/fluttercountertutorial?id=blocobserver
英文:
This is just a very wild guess, but it might be a race condition. Can you make the method async
and add a delay before printing out the state?
Also, what I usually do is to use a Bloc Observer to monitor state changes:
class _DebugBlocObserver extends BlocObserver {
@override
void onChange(BlocBase<dynamic> bloc, Change<dynamic> change) {
super.onChange(bloc, change);
log('onChange(${bloc.runtimeType}, $change)');
}
@override
void onError(BlocBase<dynamic> bloc, Object error, StackTrace stackTrace) {
log('onError(${bloc.runtimeType}, $error, $stackTrace)');
super.onError(bloc, error, stackTrace);
}
}
You can then register this observer when starting your app:
Bloc.observer = _DebugBlocObserver();
This prints out all state changes.
Here is the documentation: https://bloclibrary.dev/#/fluttercountertutorial?id=blocobserver
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论