Reputation: 308
Problem: Shared preference bool value is null
on startup even though I have given it a value if prefs.getBool('myBool')
returns null
(though my shared preferences value should already be set and saved). It does, however, work by the time I press a button (I assume because it has finished running the async code).
Question: How can I force shared preferences to load on startup (so my value is not null
) without having to press the print button?
Example Code:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
@override
createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
final padding = const EdgeInsets.all(50.0);
@override
void initState() {
super.initState();
MySharedPreferences.load();
MySharedPreferences.printMyBool();
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
body: new Padding(
padding: padding,
child: new Column(
children: <Widget>[
new Padding(
padding: padding,
child: new RaisedButton(
child: new Text('Save True'),
onPressed: () => MySharedPreferences.save(myBool: true),
),
),
new Padding(
padding: padding,
child: new RaisedButton(
child: new Text('Save False'),
onPressed: () => MySharedPreferences.save(myBool: false),
),
),
new Padding(
padding: padding,
child: new RaisedButton(
child: new Text('Print myBool'),
onPressed: () => MySharedPreferences.printMyBool(),
),
),
],
),
),
),
);
}
}
class MySharedPreferences {
static bool _myBool;
static void load() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
_myBool = prefs.getBool('myBool') ?? false;
}
static void save({myBool: bool}) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
_myBool = myBool;
await prefs.setBool('myBool', _myBool);
}
static void printMyBool() {
print('myBool: ${_myBool.toString()}');
}
}
Results:
On startup, myBool: null
is printed. Once the button is pressed, myBool: false/true
is then printed.
Upvotes: 23
Views: 33495
Reputation: 4283
For any one still experiencing this issue, it's because there is still a race condition in the accepted answer.
To fix it, use this package to wait for the layout to load first
Upvotes: 0
Reputation: 5279
Add condition ?? when you get value from preference.
int intValue = prefs.getInt('intValue') ?? 0;
Upvotes: 8
Reputation: 34160
Use conditional operator(??) to assign values if shared preference returning null
bool _testValue;
@override
void initState() {
super.initState();
SharedPreferences.getInstance().then((prefValue) => {
setState(() {
_name = prefValue.getString('name')?? false;
_controller = new TextEditingController(text: _name);
})
});
}
Upvotes: 3
Reputation: 51682
Your problem is that you call load() and printMyBool() in quick succession. Because load() is async calling it hasn't executed any of its code, it has only scheduled it. So, printMyBool executes before the body of load.
There's no need to put static functions in a class - just declare them as top level functions. Also, you don't really want _myBool to be a global - it should be part of a Widget's state. That way when you update it, Flutter knows what parts of your tree to redraw.
I've restructured your code to remove the redundant statics.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
@override
createState() => new MyAppState();
}
const EdgeInsets pad20 = const EdgeInsets.all(20.0);
const String spKey = 'myBool';
class MyAppState extends State<MyApp> {
SharedPreferences sharedPreferences;
bool _testValue;
@override
void initState() {
super.initState();
SharedPreferences.getInstance().then((SharedPreferences sp) {
sharedPreferences = sp;
_testValue = sharedPreferences.getBool(spKey);
// will be null if never previously saved
if (_testValue == null) {
_testValue = false;
persist(_testValue); // set an initial value
}
setState(() {});
});
}
void persist(bool value) {
setState(() {
_testValue = value;
});
sharedPreferences?.setBool(spKey, value);
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Padding(
padding: pad20,
child: new Text(
_testValue == null ? 'not ready' : _testValue.toString()),
),
new Padding(
padding: pad20,
child: new RaisedButton(
child: new Text('Save True'),
onPressed: () => persist(true),
),
),
new Padding(
padding: pad20,
child: new RaisedButton(
child: new Text('Save False'),
onPressed: () => persist(false),
),
),
new Padding(
padding: pad20,
child: new RaisedButton(
child: new Text('Print myBool'),
onPressed: () => print(_testValue),
),
),
],
),
),
),
);
}
}
Upvotes: 15