Reputation: 2128
I have one screen to display data from shared preferences. I already success save and get data from shared preferences. Then I have a flow in one screen like this:
I get the logic for that flow, but the problem is, before data showing in the screen (number 2), it shows button login first for a few milliseconds then show the data. Why did it happen? It's not got data from API / internet and I'm not using FutureBuilder, I just using Shared Preferences. How to kill this delayed? Below is my full code:
class MorePage extends StatefulWidget {
@override
_MorePageState createState() => _MorePageState();
}
class _MorePageState extends State<MorePage> {
bool isLoading = false;
SessionManager _sessionManager = SessionManager();
int status;
@override
void initState() {
super.initState();
_sessionManager.getStatusLogin().then((value) { //i use this for get status code login success
setState(() {
status = value;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: color_grey_bg,
body: SafeArea(
child: getMorePage(),
),
);
}
Widget getMorePage() {
return ListView(
physics: ClampingScrollPhysics(),
children: <Widget>[
Container(
padding: EdgeInsets.only(
left: MediaQuery.of(context).size.width / 20,
),
height: MediaQuery.of(context).size.width / 4,
width: MediaQuery.of(context).size.width,
color: color_white,
child: setProfile(),
),
],
);
}
Widget setProfile() {
if (status == 200) { // i use this logic to show widget with status login, but it's have delayed like show data from API. How to kill it? Because I using SharedPreferences, not hit the API
return profileUser();
} else {
return notSignIn();
}
}
Widget profileUser() {
return Row(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
name,
style: TextStyle(
color: color_grey_text,
fontSize: MediaQuery.of(context).size.width / 26,
fontWeight: FontWeight.bold,
),
),
Text(
email,
style: TextStyle(
color: color_grey_text,
fontSize: MediaQuery.of(context).size.width / 30,
fontWeight: FontWeight.normal,
),
),
Text(
role,
style: TextStyle(
color: color_grey_text,
fontSize: MediaQuery.of(context).size.width / 35,
fontWeight: FontWeight.normal,
),
),
],
),
Spacer(),
IconButton(
icon: Icon(
Icons.arrow_forward_ios,
size: MediaQuery.of(context).size.height / 40,
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => DetailUserPage()));
},
),
],
);
}
Widget notSignIn() {
return Padding(
padding:
EdgeInsets.only(left: 50.0, right: 50.0, top: 30.0, bottom: 30.0),
child: RaisedGradientButton(
child: Text(
'Login',
style: TextStyle(
color: color_white,
fontSize: MediaQuery.of(context).size.width / 25),
),
gradient: LinearGradient(
colors: <Color>[color_blue, color_green],
),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()));
},
),
);
}
}
And this is class SessionManager for create function of shared_preferences:
class SessionManager {
.....
getStatusLogin() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
int status = preferences.getInt("status");
return status;
}
....
}
Upvotes: 0
Views: 3289
Reputation: 496
the getprofile function is actually is a future , you used the async await
keywords .
it's true that retrieving the data from the sharedpref doesn't take time ,but getting the instance of the sharedpref is the root of the cause . so you have to options to solve this solution .
1-getting the instance of the shared pref in the main function. you can get the instance of the shared pref and pass it as argument to the whole application.
Example :
void main ()async{
final instance = await sharedPreference.getInstance();
runApp(MyApp(instance));}
now in your MorePage widget
class _MorePageState extends State<MorePage> {
LoginStatus _loginStatus = LoginStatus.notSignIn;
SessionManager _sessionManager = SessionManager();
String name, email, role;
//no need for the async keyword
getProfile() { //this func just for show the data
name = widget.preferences.getString("fullname");
email = widget.preferences.getString("email");
role = widget.preferences.getString("role");
}
@override
void initState() {
super.initState();
getProfile();
_sessionManager.getLoginStatus().then((value) { //this code for get the status of login
setState(() {
_loginStatus = value;
});
});
}
now the getProfile function is not async which means there's no milliseconds that makes that weird behavior at the beginning .
2-Make another enum value 'busy' (simpler solution) . simply you can leave you code as it's but add a new enum value which is busy to give hint to the user that the app is checking if he has logined before or not ,you simply will give him that hint in the set profile function , you'll create another condition if ( _loginStatus == LoginStatus.busy ) return Text('checking user Info')
.
hope that helps !
Edit : You this package get_it to make a singleton instance of the session manager class and you can access it anywhere .
GetIt locator = GetIt();
void setUpLocator() {
locator.registerLazySingleton(() => SessionManager());
}
void main() async {
setUpLocator();
await locator.get<SessionManager>().getStatusLogin();
runApp(MyApp());
}
class MorePage extends StatefulWidget {
@override
_MorePageState createState() => _MorePageState();
}
class _MorePageState extends State<MorePage> {
bool isLoading = false;
final _sessionManager = locator.get<SessionManager>();
int status;
@override
void initState() {
super.initState();
//make property of statuesif you don't have property of the statues
//in the session manager class
status = _sessionManager.statues;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: color_grey_bg,
body: SafeArea(
child: getMorePage(),
),
);
}
Widget getMorePage() {
return ListView(
physics: ClampingScrollPhysics(),
children: <Widget>[
Container(
padding: EdgeInsets.only(
left: MediaQuery.of(context).size.width / 20,
),
height: MediaQuery.of(context).size.width / 4,
width: MediaQuery.of(context).size.width,
color: color_white,
child: setProfile(),
),
],
);
}
Widget setProfile() {
if (status == 200) {
// i use this logic to show widget with status login, but it's have delayed like show data from API. How to kill it? Because I using SharedPreferences, not hit the API
return profileUser();
} else {
return notSignIn();
}
}
Widget profileUser() {
return Row(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
name,
style: TextStyle(
color: color_grey_text,
fontSize: MediaQuery.of(context).size.width / 26,
fontWeight: FontWeight.bold,
),
),
Text(
email,
style: TextStyle(
color: color_grey_text,
fontSize: MediaQuery.of(context).size.width / 30,
fontWeight: FontWeight.normal,
),
),
Text(
role,
style: TextStyle(
color: color_grey_text,
fontSize: MediaQuery.of(context).size.width / 35,
fontWeight: FontWeight.normal,
),
),
],
),
Spacer(),
IconButton(
icon: Icon(
Icons.arrow_forward_ios,
size: MediaQuery.of(context).size.height / 40,
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailUserPage()));
},
),
],
);
}
Widget notSignIn() {
return Padding(
padding:
EdgeInsets.only(left: 50.0, right: 50.0, top: 30.0, bottom: 30.0),
child: RaisedGradientButton(
child: Text(
'Login',
style: TextStyle(
color: color_white,
fontSize: MediaQuery.of(context).size.width / 25),
),
gradient: LinearGradient(
colors: <Color>[color_blue, color_green],
),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()));
},
),
);
}
}
Upvotes: 2
Reputation: 5182
I think you should create a class and then use reference -:
Future<void> main() async{
ShareP.preferences = await SharedPreferences.getInstance();
}
class ShareP {
static SharedPreferences preferences;
}
Now you can refer it ("ShareP.preferences") and get your SharedPreference values
Upvotes: 0
Reputation: 409
I think show Circle Progress once getting values form shared pref then show main container.
Please check below code:-
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: color_grey_bg,
body: SafeArea(
child: LoginStatus.notSignIn ? const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Color(colorPrimary))),
) : getMorePage()
),
);
}
Upvotes: 0