Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

dart - Flutter: Shared Preferences null on Startup

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...