Flutter: Shared Preferences null при запуске

PityTheFool спросил: 28 марта 2018 в 02:42 в: dart

Проблема: общее значение предпочтения 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.

2 ответа

Есть решение
Richard Heap ответил: 28 марта 2018 в 03:41

Ваша проблема в том, что вы вызываете load () и printMyBool () в быстрой последовательности. Поскольку load () является асинхронным вызовом, он не выполнил ни одного своего кода, он только запланировал это. Итак, printMyBool выполняется перед телом загрузки.

Нет необходимости помещать статические функции в класс - просто объявите их как функции верхнего уровня. Кроме того, вы не хотите, чтобы _myBool был глобальным - он должен быть частью состояния виджета. Таким образом, когда вы обновляете его, 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),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
Simon ответил: 26 апреля 2018 в 08:02
У меня та же проблема - мои sharedPreferences возвращают ноль при запуске. Почему они не могут сделать sharedPreferences синхронными, как Android sharedPreferences, вместо асинхронных? Async только вызывает проблемы.
kemdo ответил: 14 июня 2018 в 12:00
это шумная проблема? У меня есть нижний элемент навигации, который раздувается сразу после сборки, но sharedpreference возвращает ноль, когда отображается первый элемент навигации? Действительно большая проблема здесь.
Richard Heap ответил: 14 июня 2018 в 12:13
Проверьте этот ответ для получения дополнительной информации stackoverflow.com/questions/51215064/…
zinwa_lin ответил: 07 мая 2018 в 07:52

Вы можете использовать FutureBuilder для выполнения асинхронных операций.