Flutter:Startup

时间:2018-04-21 16:22:50

标签: dart sharedpreferences flutter

问题:启动时共享首选项bool值为null,即使我在prefs.getBool('myBool')返回null时给它一个值(尽管我的共享首选项值已经设置并保存) 。但是,按下按钮时它确实有效(我假设它已经完成了异步代码的运行)。

问题:如何在不必按下打印按钮的情况下强制启动时加载共享首选项(因此我的值不是null)?

示例代码:

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()}');
  }
}

结果:   启动时,会打印myBool: null。按下按钮后,将打印myBool: false/true

6 个答案:

答案 0 :(得分:5)

您的问题是您快速连续调用load()和printMyBool()。因为load()是异步调用它没有执行任何代码,所以它只安排了它。因此,printMyBool在加载体之前执行。

不需要在类中放置静态函数 - 只需将它们声明为顶级函数即可。此外,你并不是真的希望_myBool成为一个全球性的 - 它应该是Widget状态的一部分。这样,当您更新它时,Flutter知道要重绘的树的哪些部分。

我重新构建了您的代码以删除冗余静态。

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

答案 1 :(得分:1)

添加条件??当您从偏好中获得价值时。

int intValue = prefs.getInt('intValue') ?? 0;

答案 2 :(得分:1)

import 'package:shared_preferences/shared_preferences.dart';
 
class MySharedPreferences {
  MySharedPreferences._privateConstructor();
 
  static final MySharedPreferences instance =
      MySharedPreferences._privateConstructor();
 
  setBooleanValue(String key, bool value) async {
    SharedPreferences myPrefs = await SharedPreferences.getInstance();
    myPrefs.setBool(key, value);
  }
 
  Future<bool> getBooleanValue(String key) async {
    SharedPreferences myPrefs = await SharedPreferences.getInstance();
    return myPrefs.getBool(key) ?? false;
  }
 
}
MySharedPreferences.instance
        .getBooleanValue("key")
        .then((value) => setState(() {
              val result = value;
            }));

更多参考:Flutter Shared Preferences Tutorial

答案 3 :(得分:0)

如果共享首选项返回null,则使用条件运算符(??)分配值

IncidentDetail.PendIncidentNbr

答案 4 :(得分:0)

对于仍然遇到此问题的任何人,这是因为接受的答案中仍然存在竞争条件。

To fix it, use this package to wait for the layout to load first

答案 5 :(得分:-1)

您可以使用FutureBuilder进行async操作。