flutter:BLoC Builder 没有更新,尽管我在调试器中看到 new/different 状态

flutter: BLoC Builder not updating, though I see new/different state in debugger

我今天发生的第二件怪事。当我在 bloc.dart(库,而不是我的文件)中跟踪调试器时,我看到 transition.nextState == state && _emittedfalse,它不会更新我的小部件(nextState 的列表大小为 2,state 有10 - _emitted 为真)。据我了解,构建器应该没问题,还有其他地方可以查看为什么它不更新吗?

在展示代码之前先解释一下逻辑

  1. 我在应用启动时使用

    获取我的数据
    BlocProvider(create: (context) =>
      LogicGraphsPStmntBloc(logicGraphsRepository:
      logicGraphsRepository)..add(LogicGraphsNextProblemRequested()),
    
  2. 这是一个包含 10 个字符串的列表,我将其存储在我的 _bloc.dart 文件中(不确定这是否是最先进的)

  3. 这 10 个字符串通过状态 LogicGraphsPStmntLoadSuccess(statements) 发送并正确呈现为按钮

  4. 如果我点击一个按钮,只会显示第一个和选择的字符串。使用 onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},

    正确触发事件
  5. 这会正确触发状态 yield LogicGraphsPStmntLoadSuccess(statementsShown);,现在列表中只有 2 个元素(与步骤 3 中的 10 个元素相比),但它不会导致重新呈现

  6. 如果我使用调试器进入状态,我可以看到两种状态都有不同数量的元素。

我的状态

abstract class LogicGraphsPStmntState extends Equatable {
  const LogicGraphsPStmntState();
  @override
  List<Object> get props => [];
}

class LogicGraphsPStmntLoadSuccess extends LogicGraphsPStmntState {
  const LogicGraphsPStmntLoadSuccess([this.statements = const []]);
  final List<String> statements;

  @override
  List<Object> get props => [];

  @override
  String toString() => 'LogicGraphsPStmntLoadSuccess { statements: $statements }';
}

我的集团(不完全是,因为我的子函数中用于释放状态的代码没有达到 my other issue 中的描述。所以目前我在 mapEventToState=[= 中将这些子函数行作为意大利面条24=]

class LogicGraphsPStmntBloc extends Bloc<LogicGraphsPStmntEvent, LogicGraphsPStmntState> {
  LogicGraphsPStmntBloc({@required this.logicGraphsRepository}) : super(LogicGraphsPStmntInProgress());
  final LogicGraphsRepository logicGraphsRepository;
  List<String> statements;
  int currentProblem = -1;

  @override
  Stream<LogicGraphsPStmntState> mapEventToState(LogicGraphsPStmntEvent event) async* {
        if (event is LogicGraphsNextProblemRequested) {
          _mapLGPStmntNewProblemRequested();
          _mapLGPStmntLoadRequested(currentProblem);
        }
        else if (event is LogicGraphsPStmntLoadRequested) {
          _mapLGPStmntLoadRequested(currentProblem);
        }
        else if (event is LogicGraphsPStmntCollapsed) {
          _mapLGPStmntCollapseRequested(event);
  }
  Stream<LogicGraphsPStmntState> _mapLGPStmntNewProblemRequested() async* {
        try {
          currentProblem =
          await getNextProblem(currentProblem == null ? -1 : currentProblem);
          statements =
          await logicGraphsRepository.getProblemStmntList(currentProblem);
          _mapLGPStmntLoadRequested(currentProblem);
        } catch (_) {
          yield LogicGraphsPStmntLoadFailure();
        }
  }
  Stream<LogicGraphsPStmntState> _mapLGPStmntLoadRequested(int problem) async* {
          try {
            yield LogicGraphsPStmntLoadSuccess(statements);
          } catch (_) {
            yield LogicGraphsPStmntLoadFailure();
          }
  }
  Stream<LogicGraphsPStmntState> _mapLGPStmntCollapseRequested(
          LogicGraphsPStmntCollapsed event) async* {
          List<String> statementsShown = [];
          statementFocussed = event.statement;
          statementsShown.add(statements[0]);
          statementsShown.add(statements[statementFocussed]);
          yield LogicGraphsPStmntLoadSuccess(statementsShown);
  }
}

我的小部件

class LogicGraphPage extends StatelessWidget {
  final LogicGraphsRepository logicGraphsRepository = LogicGraphsRepository(
      logicGraphsApiClient: LogicGraphsApiClient());

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: BlocProvider(
        create: (context) =>
        LogicGraphsPStmntBloc(logicGraphsRepository: logicGraphsRepository)
          ..add(LogicGraphsNextProblemRequested()),
          child:BlocBuilder<LogicGraphsPStmntBloc, LogicGraphsPStmntState>(
            builder: (context, state) {
              if (state is LogicGraphsPStmntLoadSuccess) {
                final List<String> statements = state.statements;
                return ListView.builder(
                    itemCount: statements.length,
                    itemBuilder: (BuildContext context, int index) {
                      return CupertinoButton(
                        padding: EdgeInsets.all(0),
                        child: Text(statements[index])
                        onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},
                      );
                    });
              }
              else return Container();
            }
        )
      ),
    );
  }
}

bloc.dart 库中的函数,我假设新状态已发出。您会看到行 if (transition.nextState == state && _emitted) return;。下一个状态有 2 个元素,状态有 10 个,_emitted 为真,所以我假设代码继续。而是触发 return 并跳过带有 emit(transition.nextState); 的行。

非常感谢任何帮助,因为这是我第一次使用 BLoC/equatable 并且一般来说 flutter 对我来说还是很新的。但我在进步!

 void _bindEventsToStates() {
    _transitionSubscription = transformTransitions(
      transformEvents(
        _eventController.stream,
            (event) => mapEventToState(event).map(
              (nextState) => Transition(
            currentState: state,
            event: event,
            nextState: nextState,
          ),
        ),
      ),
    ).listen(
          (transition) {
        if (transition.nextState == state && _emitted) return; // <<<<<<<<<<<
        try {
          onTransition(transition);
          emit(transition.nextState);
        } on dynamic catch (error, stackTrace) {
          onError(error, stackTrace);
        }
        _emitted = true;
      },
      onError: onError,
    );
  }

我猜 bloc 无法分辨 LogicGraphsPStmntLoadSuccess(statements)LogicGraphsPStmntLoadSuccess(statementsShown) 之间的区别,因为它们是相同的状态,我认为它无法发现不同参数之间的差异。

所以我建议这样做: 在产生 LogicGraphsPStmntLoadSuccess(statementsShown) 之前尝试产生一个“切换”状态,就像我之前不知道 LogicGraphsPStmntChangeStatement 一样。 所以:

yield LogicGraphsPStmntChangeStatement;
yield LogicGraphsPStmntLoadSuccess(statementsShown);

这应该可以解决问题。