Reputation: 389
I'm trying to add a shared preference to my application to save the user's data for the next login but I get an error and I have an infinite loop of loading data and my application crashed after this loop.
this is the error which I get
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: setState() called after dispose(): _SplashScreenState#e691a(lifecycle state: defunct, not mounted) E/flutter ( 2799): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. E/flutter ( 2799): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree. E/flutter ( 2799): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
and this is the method to get preference in my splash screen
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isLog = prefs.getBool("islog");
print(this.mounted);
if(this.mounted){
if (isLog == true) {
setState(() {
String email = prefs.getString("email");
String pass = prefs.getString("pass");
signIn(email, pass);
});
}
}else {
if(!mounted)
setState(() {
isLoading = false;
});
}
}
signIn(String email, String pass) async {
var res = await userProvider.login(email, pass);
var user = userProvider.user.tourist;
if (res is FailedRequest) {
Dialogs.showErrorDialog(context, message: res.message, code: res.code);
} else if (user == true) {
print("Shared ***********************************************");
await appProvider.countryList();
await appProvider.activityList();
await appProvider.tourGuideList();
setState(() {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => BottomTourist()));
});
}
and this is my splash screen widget
@override
Widget build(BuildContext context) {
userProvider = Provider.of<UserProvider>(context, listen: false);
appProvider = Provider.of<AppProvider>(context, listen: false);
init();
return Container(
child: Scaffold(
body: Stack(
children: <Widget>[
Container(
foregroundDecoration: !AppTheme.isLightTheme
? BoxDecoration(
color:
AppTheme.getTheme().backgroundColor.withOpacity(0.4))
: null,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Image.asset('assets/images/introduction.jpg',
fit: BoxFit.cover),
),
Column(
children: <Widget>[
Expanded(
flex: 1,
child: SizedBox(),
),
Center(
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
boxShadow: <BoxShadow>[
BoxShadow(
color: AppTheme.getTheme().dividerColor,
offset: Offset(1.1, 1.1),
blurRadius: 10.0),
],
),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
child: Image.asset('assets/images/appIcon.png'),
),
),
),
SizedBox(
height: 16,
),
Expanded(
flex: 4,
child: SizedBox(),
),
Padding(
padding: const EdgeInsets.only(
left: 48, right: 48, bottom: 8, top: 8),
child: Container(
height: 48,
decoration: BoxDecoration(
color: AppTheme.getTheme().primaryColor,
borderRadius: BorderRadius.all(Radius.circular(24.0)),
boxShadow: <BoxShadow>[
BoxShadow(
color: AppTheme.getTheme().dividerColor,
blurRadius: 8,
offset: Offset(4, 4),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(24.0)),
highlightColor: Colors.transparent,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => IntroductionScreen()),
);
},
child: Center(
child: Text(
"Get started",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
color: Colors.white),
),
),
),
),
),
),
],
),
],
),
),
);
}
}
and this is my login method which use to set preference for the user
signIn() async {
var res = await userProvider.login(
_userNameController.text, _passwordController.text);
var user = userProvider.user.tourist;
SharedPreferences prefs = await SharedPreferences.getInstance();
if (res is FailedRequest) {
Dialogs.showErrorDialog(context, message: res.message, code: res.code);
} else if (user == true) {
print("Signing in success");
await appProvider.countryList();
await appProvider.activityList();
await appProvider.tourGuideList();
setState(() {
prefs.setBool("islog", true);
prefs.setString('pass', userProvider.user.password);
prefs.setString('email', userProvider.user.email);
Navigator.pushReplacement(widget._context,
MaterialPageRoute(builder: (context) => BottomTourist()));
});
}
so can anyone help me with my issue?
Upvotes: 2
Views: 1503
Reputation: 11481
You are calling setState
in an async
method named 'signIn()'
without checking whether the widget is alive or not.
You need to set up a well-defined state management system for your app. Read this for more info.
Steps:
boolean
variable in your state class to identify whether the widget is alive or not.Upvotes: 1