Слушатель блока Flutter не слушает изменения состояния

Я использую библиотеку flutter_bloc для создания страницы с кодом подтверждения. Вот что я пытался сделать.

class PhonePage extends StatelessWidget {
  static Route route() {
    return MaterialPageRoute<void>(builder: (_) => PhonePage());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        create: (_) =>
            ValidationCubit(context.repository<AuthenticationRepository>()),
        child: PhoneForm(),
      ),
    );
  }
}

class PhoneForm extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocConsumer<ValidationCubit, ValidationState>(
      listener: (context, state) {
        print('Listener has been called');
        if (state.status.isSubmissionFailure) {
          _showVerificationError(context);
        } else if (state.status.isSubmissionSuccess) {
          _showVerificationSuccess(context);
        }
      },
      builder: (context, state) {
        return Container(
          child: SingleChildScrollView(
            child: Padding(
              padding: EdgeInsets.all(16.0),
              child: Column(
                mainAxisSize: MainAxisSize.max,
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  _HeaderAndTitle(),
                  _VerificationInput(),
                  _VerifyButton()
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  void _showVerificationError(context) {
    Scaffold.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(const SnackBar(content: Text('Validation error')));
  }

  void _showVerificationSuccess(context) {
    Scaffold.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(const SnackBar(
        content: Text('Validation Success'),
        backgroundColor: Colors.green,
      ));
  }
}

...

class _VerifyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<ValidationCubit, ValidationState>(
        builder: (context, state) {
      return RaisedButton.icon(
          color: Colors.blue,
          padding: EdgeInsets.symmetric(horizontal: 38.0, vertical: 12.0),
          textColor: Colors.white,
          icon: state.status.isSubmissionInProgress
              ? Icon(FontAwesomeIcons.ellipsisH)
              : Icon(null),
          label: Text(state.status.isSubmissionInProgress ? '' : 'Verify',
              style: TextStyle(fontSize: 16.0)),
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
          onPressed: state.status.isValid
              ? () => context.bloc<ValidationCubit>().verifyCode()
              : null);
    });
  }
}

Теперь функция verifyCode () является асинхронной функцией, определенной внутри ValidationCubit. Он генерирует состояния со статусом загрузки, успешным и неудачным. Однако слушатель не улавливает эти изменения и не показывает закусочные. Я не мог понять почему? Я также использую библиотеку Formz, как это предлагается в документации flutter_bloc. Вот часть verifyCode.

Future<void> verifyCode() async {
    if (!state.status.isValidated) return;
    emit(state.copyWith(status: FormzStatus.submissionInProgress));
    try {
      // send validation code to server here
      await _authenticationRepository.loginWithEmailAndPassword(
          email: '[email protected]', password: '12');
      emit(state.copyWith(status: FormzStatus.submissionSuccess));
    } on Exception {
      emit(state.copyWith(status: FormzStatus.submissionFailure));
    }
  }

Модель кода проверки выглядит так:

class ValidationState extends Equatable {
  final VerificationCode verificationCode;
  final FormzStatus status;

  const ValidationState({this.verificationCode, this.status});

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

  ValidationState copyWith(
      {VerificationCode verificationCode, FormzStatus status}) {
    return ValidationState(
        verificationCode: verificationCode ?? this.verificationCode,
        status: status ?? this.status);
  }
}

И класс состояния проверки:

class ValidationState extends Equatable {
  final VerificationCode verificationCode;
  final FormzStatus status;

  const ValidationState({this.verificationCode, this.status});

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

  ValidationState copyWith(
      {VerificationCode verificationCode, FormzStatus status}) {
    return ValidationState(
        verificationCode: verificationCode ?? this.verificationCode,
        status: status ?? this.status);
  }
}

person Merhawi Fissehaye    schedule 04.11.2020    source источник
comment
Я не знаю, какие есть блочные государства. Я знаю, что 'listner' запускается, когда состояние изменяется с другого состояния ..   -  person KuKu    schedule 04.11.2020
comment
печатает ли он print («Слушатель был вызван»); ??   -  person xbadal    schedule 04.11.2020
comment
добавьте свой класс состояния или состояния, которые вы определили.   -  person xbadal    schedule 04.11.2020
comment
@xbadal Я обновил его, включив в него классы состояния и модели. Он не печатает, что прослушиватель был вызван при нажатии кнопки.   -  person Merhawi Fissehaye    schedule 04.11.2020
comment
вы не уступаете государству. так что в основном состояние не меняется. вот почему он не печатается.   -  person xbadal    schedule 04.11.2020


Ответы (2)


Думаю, проблема в вашем государственном классе.

слушатель вызывается только один раз для каждого изменения состояния (НЕ включая начальное состояние), в отличие от builder в BlocBuilder, и является функцией void.

Каждый раз, когда Cubit генерирует новое состояние, оно сравнивается с предыдущим, и если они РАЗНЫЕ, запускается функция прослушивателя.

В вашей ситуации вы используете Equatable только с verificationCode как props, что означает, что при сравнении двух состояний проверяются только verificationCode. Таким образом, потребитель BLoC считает, что два состояния равны, и не запускает функцию прослушивателя снова.

Если вы проверите свою verifyCode() функцию, единственным изменяющимся параметром будет status.

Чтобы исправить это, добавьте свойство status в список props в вашем классе состояния.

  @override
  List<Object> get props => [this.verificationCode, this.status];
person jorjdaniel    schedule 09.11.2020

если вы хотите обновить то же состояние, просто добавьте одно состояние перед вызовом состояния обновления, как это, если вы хотите обновить состояние «Загружено», снова вызовите состояние «Загрузка» перед этим, а затем вызовите состояние «Загружено», чтобы BlocListener и BlocBuilder прослушали его

Отредактировано. Я изменил using bloc на cubit для этого, и cubit может постоянно излучать одно и то же состояние, а bloclistener и blocbuilder могут его слушать.

person markand chauhan    schedule 01.06.2021
comment
Пожалуйста, поделитесь коротким примером кода в своем ответе - person Marcel Hofgesang; 02.06.2021
comment
попробуйте использовать Cubit, он может излучать то же состояние, а bloclistener и blocbuilder могут его слушать - person markand chauhan; 03.06.2021