【问题标题】:Flutter: Shared Preferences null on StartupFlutter:启动时共享首选项为空
【发布时间】:2018-10-02 03:01:04
【问题描述】:

问题:共享首选项 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

【问题讨论】:

    标签: dart sharedpreferences flutter


    【解决方案1】:

    您的问题是您连续调用 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),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }
    

    【讨论】:

    • 我有同样的问题 - 我的 sharedPreferences 在启动时返回 null。为什么他们不能像 Android sharedPreferences 那样使 sharedPreferences 同步而不是异步?异步只会导致问题。
    • 这是一个嘈杂的问题?我的底部导航项在构建后立即膨胀,但是当第一个导航项显示时 sharedpreference 返回 null?这里真的是个大问题。
    • 查看此答案以获取更多信息stackoverflow.com/questions/51215064/…
    • 这些答案都没有帮助我。我的Shared_Preferences do not persist
    • 此解决方案不起作用。您无法在小部件加载之前设置状态。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      bool _testValue;
      
      @override
        void initState() {
          super.initState();
          SharedPreferences.getInstance().then((prefValue) => {
            setState(() {
              _name = prefValue.getString('name')?? false;
              _controller = new TextEditingController(text: _name);
            })
          });
        }
      

      【讨论】:

        【解决方案4】:
        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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-10-01
              • 2021-03-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多