簡體   English   中英

未處理的異常:錯誤 state:調用關閉后無法添加新事件?

[英]Unhandled Exception: Bad state: Cannot add new events after calling close?

我正在制作一個登錄功能,我正在做出響應以了解響應是成功還是失敗。 可以看到我的 BLOC 編碼。 登錄過程成功但是當我想在注銷后返回登錄頁面時出現錯誤未處理的異常:Bad state:調用關閉后無法添加新事件。 我該如何處理?

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 }

集團:

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();
    });
  }
}

問題是您已經在全局范圍內創建了一個 bloc 實例(這不是一個好習慣),並且在登錄過程完成后,您調用login.dispose()來關閉 LoginBloc 中的所有流,並且您可以'不要將新事件添加到已關閉的流中。

您最好在 LoginPage initState方法中創建 LoginBloc 的實例,並在dispose方法中關閉它。 這樣,每當您導航到登錄頁面時,都會創建一個新塊並按預期工作。

更新:一個簡單的例子:

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();
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM