Я делаю функцию входа в систему, я делаю горячие ответы, чтобы узнать, были ли ответы успешными или неудачными. можно увидеть мою кодировку 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();
});
}
}