'Flutter : SharedPreferences not fetching value at app start
I am trying to store a value and based on the value I want to navigate to LandinPage or HomePage. However when my app loads I am not able to get the SharedPreferences value. Currently, the value is set on click of a button in Landing page, and when I close/minimize the app. I don't even get to see the print messages from main.dart and can't fetch values. What am I doing wrong?
Here is my code:
import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<MyApp> {
@override
void initState() {
super.initState();
getUserStatus().then((userStatus) {
if (userStatus == null) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return LandingPage();
}));
} else {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return HomePage();
}));
}
});
}
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
));
}
}
Future<String> getUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
return userStatus;
}
Solution 1:[1]
You've declared a method main of MyApp but it never gets called. The main that starts the app is the one with runApp in it. You could move the prefs.getString() into the real main (having made it async) and then pass the value into the MyApp widget as a parameter.
Solution 2:[2]
I feel like Willie's answer may be just as good, but here's another approach.
Overall, my approach would be to load the main home page automatically, and then in the initstate of the home page, check to see if this is the user's first visit to the app. If so, pop the landing page on top immediately. I've used this approach successfully without the user having a poor experience.
Below is the default app but with your SharedPreferences code moved to the appropriate spot.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
var userStatus;
//If user status is null, then show landing page.
Future<void> checkUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
if (userStatus == null) {
Navigator.push(context, MaterialPageRoute(builder: (context) => LandingPage()));
}
}
@override
void initState() {
super.initState();
//Call check for landing page in init state of your home page widget
checkUserStatus();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class LandingPage extends StatefulWidget {
@override
_LandingPageState createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
@override
Widget build(BuildContext context) {
//Build landing page here.
return Container();
}
}
Solution 3:[3]
I know this question is old and already been answered but for my situation, Richard Heap's answer was more suitable so I would like to add a code snippet for others.
I only cite part of it, so please modify it if you are going to use it for your app. After the Landing/Welcome page is viewed by user, update the preference by setBool and it won't show up after that.
void main() async {
// do whatever
SharedPreferences prefs = await SharedPreferences.getInstance();
bool hideWelcome = prefs.getBool('hideWelcome') ?? false;
// start your app
runApp(MyApp(hideWelcome));
}
class MyApp extends StatelessWidget {
final hideWelcome;
MyApp(this.hideWelcome);
@override
Widget build(BuildContext context) {
return MaterialApp(
// other setting like theme, title
initialRoute: hideWelcome ? '/' : '/welcome',
routes: {
'/': (context) => MyHomePage(),
'/welcome': (context) => WelcomePage(),
// other pages
}
);
}
Solution 4:[4]
you must add
@override
void initState() {
getUserStatus();
super.initState();
}
var name;
void getUserStatus() async {
SharedPreferences prefs= await SharedPreferences.getInstance();
setState(() {
userStatus = prefs.getString("userStatus");
});
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Richard Heap |
| Solution 2 | Eric Duffett |
| Solution 3 | |
| Solution 4 | Arif Maksum |
