Необработанное исключение: Плохое состояние: не удается добавить новые события после вызова close? - PullRequest
0 голосов
/ 23 апреля 2020

Я делаю функцию входа в систему, я делаю горячие ответы, чтобы узнать, были ли ответы успешными или неудачными. можно увидеть мою кодировку BLO C. процесс входа был успешным, но когда я хочу вернуться на страницу входа после выхода из системы, появляется ошибка Unhandled Exception: Bad state: Невозможно добавить новые события после вызова close. как я могу справиться с этим?

ОТВЕТЫ API:

class ApiResponse<T> {
  Status status;
  T data;
  String message;

  ApiResponse.loading(this.message) : status = Status.LOADING;

  ApiResponse.completed(this.data) : status = Status.COMPLETED;

  ApiResponse.error(this.message) : status = Status.ERROR;

//  @override
//  String toString() {
//    return "Status : $status \n Message : $message \n Data : $data";
//  }
}

enum Status { LOADING, COMPLETED, ERROR }

BLO C:

class LoginBloc extends Object with Validators{
  final _repository = EresidenceRepository();
  final _userid = BehaviorSubject<String>();
  final _password = BehaviorSubject<String>();
  final _imei = BehaviorSubject<String>();
  final _coordinate = BehaviorSubject<String>();
  final BehaviorSubject<ApiResponse<login_responses>> _subject = BehaviorSubject<ApiResponse<login_responses>>();

  Function(String) get userid => _userid.sink.add;
  Function(String) get password => _password.sink.add;
  Function(String) get imei => _imei.sink.add;
  Function(String) get coordinate => _coordinate.sink.add;

  Stream<String> get useridValidation => _userid.stream.transform(useridValidator);
  Stream<String> get passwordValidation => _password.stream.transform(passwordValidator);
  Stream<bool> get submitCheck => Rx.combineLatest2(useridValidation, passwordValidation, (e,p) => true);

  login() async {
    _subject.sink.add(ApiResponse.loading("Logging In..."));
    try {
      login_responses response = await _repository.login(
          _userid.value, _password.value, _imei.value, _coordinate.value);

      prefsBloc.changePrefsLogin(
          PrefsState(false, response.data.userid, response.data.password, _imei.value, _coordinate.value, "")
      );

      _subject.sink.add(ApiResponse.completed(response));

      print(response);

    } catch (e) {
      _subject.sink.add(ApiResponse.error(e.toString()));
      print(e);
    }
  }

  dispose(){
    _userid.close();
    _password.close();
    _imei.close();
    _coordinate.close();
    _subject.close();
  }

  BehaviorSubject<ApiResponse<login_responses>> get subject => _subject;

}

final login = LoginBloc();

Пользовательский интерфейс:

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> with WidgetsBindingObserver{

  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  FocusNode passwordFocusNode, useridFocusNode;

  @override
  void initState() {
    super.initState();

    prefsBloc.checkLoginPref(context);


    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {

    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }


  @override
  Widget build(BuildContext context) {
    return AnnotatedRegion<SystemUiOverlayStyle>(
        value: SystemUiOverlayStyle.dark,
        child: Scaffold(
          backgroundColor: Colors.white,
          body: StreamBuilder(
              stream: login.subject,
              builder: (context, AsyncSnapshot<ApiResponse<login_responses>> snapshot){
                if(snapshot.hasData) {
                  print(snapshot.data.status);
                  switch (snapshot.data.status) {
                    case Status.LOADING:
                      _onWidgetDidBuild((){
                        Scaffold.of(context).showSnackBar(
                            SnackBar(
                              content: Row(
                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                children: [
                                  Text(snapshot.data.message),
                                  CircularProgressIndicator(),
                                ],
                              ),
                              backgroundColor: Colors.black,
                            ),
                          );
                      });
                      break;
                    case Status.COMPLETED:
                      login_responses result = snapshot.data.data;
                      if(result.data.bit70 == "000") {
                        _onWidgetDidBuild((){
                          login.dispose();
                          AppRoutes.replace(context, LoginVerifyPage());
                        });
                      }else{
                        _onWidgetDidBuild((){
                          login.dispose();
                          AppRoutes.replace(context, MainApp());
                        });
                      }
                      break;
                    case Status.ERROR:
                      _onWidgetDidBuild(() {
                        Scaffold.of(context).showSnackBar(SnackBar(
                          content: Text('${snapshot.data.message}'),
                          backgroundColor: Colors.red,
                        ));
                      });
                      break;
                  }
                }
                return _formLogin();
              }
          ),
        )
    );
  }

  _formLogin() {
    return SafeArea(
      child: Container(
        child: Column(
          children: <Widget>[
            Expanded(
                flex: 1,
                child: Container(
                    padding: EdgeInsets.symmetric(horizontal: SizeConfig.widthMultiplier * 1, vertical: SizeConfig.heightMultiplier * 1),
                    child: CachedNetworkImage(
                      imageUrl: "https://images.glints.com/unsafe/1024x0/glints-dashboard.s3.amazonaws.com/company-logo/68545821966f833d182f98775c73c7ae.png",
                      errorWidget: (context, url, error) => Icon(Icons.broken_image),
                      fit: BoxFit.fill,
                    ),
                )
            ),
            Expanded(
                flex: 2,
                child: Container(
                    padding: EdgeInsets.all(SizeConfig.heightMultiplier * 2),
                    child: Column(
                      children: <Widget>[
                        Container(
                            child: StreamBuilder<String>(
                              stream: login.useridValidation,
                              builder: (context, snapshot) => DataTextField(
                                errorText: snapshot.error,
                                hintText: "No Handphone",
                                textInputAction: TextInputAction.next,
                                icon: Icons.phone,
                                onSubmitted: () => FocusScope.of(context).requestFocus(passwordFocusNode),
                                onChanged: login.userid,
                                keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true),
                              ),
                            )
                        ),
                        Container(
                            margin: EdgeInsets.only(top: SizeConfig.heightMultiplier * 2),
                            child: StreamBuilder<String>(
                              stream: login.passwordValidation,
                              builder: (context, snapshot) => PasswordTextField(
                              errorText: snapshot.error,
                                hintText: "Password",
                                textInputAction: TextInputAction.done,
                                onSubmitted: () {
                                  FocusScope.of(context).requestFocus(FocusNode());
                                },
                                onChanged: login.password,
                                focusNode: passwordFocusNode,
                              ),
                            )
                        ),
                        Container(
                            width: SizeConfig.screenWidth,
                            margin: EdgeInsets.only(top: SizeConfig.heightMultiplier * 2.5),
                            child: GestureDetector(
                              onTap: () => AppRoutes.push(context, ForgotPasswordPage()),
                              child: Text(
                                Strings.titleForgotPass+" ?",
                                style: AppTheme.styleSubTitlePurpel,
                                textAlign: TextAlign.right,
                              ),
                            )
                        ),
                        Container(
                          width: SizeConfig.screenWidth,
                          margin: EdgeInsets.only(top: SizeConfig.heightMultiplier * 5),
                          child: StreamBuilder<bool>(
                            stream: login.submitCheck,
                            builder: (context, snapshot) => AppButton(
                                onPressed: snapshot.hasData ? () => login.login() : null,
                                text: Strings.signin
                            ),
                          )
                        )
                      ],
                    )
                )
            ),
            Expanded(
                flex: 1,
                child: Container(
                    alignment: Alignment.bottomCenter,
                    margin: EdgeInsets.only(bottom: SizeConfig.heightMultiplier * 2.5),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text(
                          Strings.dontAccount,
                          style: AppTheme.styleSubTitleBlackSmall,
                          textAlign: TextAlign.right,
                        ),
                        Container(
                            margin: EdgeInsets.only(left: SizeConfig.widthMultiplier * 1),
                            child: InkWell(
                              onTap: () => AppRoutes.push(context, RegistrationPage()),
                              child: Text(
                                Strings.registration,
                                style: AppTheme.styleSubTitlePurpel,
                                textAlign: TextAlign.right,
                              ),
                            )
                        )
                      ],
                    )
                )
            )
          ],
        ),
      ),
    );
  }

  void _onWidgetDidBuild(Function callback) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      callback();
    });
  }
}

1 Ответ

0 голосов
/ 23 апреля 2020

Проблема в том, что вы создали глобальный экземпляр своего блоба c (что не очень хорошо), и после завершения процедуры входа вы вызвали login.dispose(), который закрывает все потоки в вашем LoginBlo c, и вы не можете добавлять новые события в закрытые потоки.

Вам лучше создать экземпляр вашего LoginBlo c в методе LoginPage initState и закрыть его в dispose метод. Таким образом, всякий раз, когда вы переходите на страницу входа, создается новый блок c, который будет работать, как и ожидалось.

ОБНОВЛЕНИЕ: простой пример:

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  LoginBloc _loginBloc;

  @override
  void initState() {
    super.initState();
    _loginBloc = LoginBloc();
  }

  @override
  void dispose() {
    _loginBloc.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...