【问题标题】:Flutter Null Safe Config Class with shared_preferences带有 shared_preferences 的 Flutter Null 安全配置类
【发布时间】:2021-08-28 19:47:12
【问题描述】:

在 Flutter 1.x 中,我使用 Flutter shared_preferences 包实现了一个 Config 类;代码如下所示:

import 'package:shared_preferences/shared_preferences.dart';

class Config {
  static final Config _config = Config._internal();

  factory Config() => _config;

  final accessTokenKey = 'accessToken';
  String _accessToken;

  SharedPreferences prefs;

  Config._internal() {
    loadData();
  }

  void loadData() async {
    prefs = await SharedPreferences.getInstance();
    _accessToken = prefs.getString(accessTokenKey) ?? '';
  }

  String get accessToken {
    return _accessToken;
  }

  set accessToken(String accessToken) {
    _accessToken = accessToken;
    _saveString(accessTokenKey, accessToken);
  }

  _saveString(String key, String value, {String printValue = ''}) {
    String printVal = printValue.length > 0 ? printValue : value;
    prefs.setString(key, value);
  }

}

我正在 Flutter 2.x 中创建一个新项目并尝试使用相同的代码,但由于与 null 安全性相关的更改,我在正确更新代码时遇到了一些困难。 包的更新文档说要像这样初始化 _prefs 对象:

Future<SharedPreferences> _prefs = SharedPreferences.getInstance();

然后使用以下命令创建一个本地首选项对象:

final SharedPreferences prefs = await _prefs;

这很好,但我不想让每个使用 shared_preferences 的类方法异步然后重新创建变量。同时,如果不先初始化它,我无法将它创建为类变量。有人可以告诉我一个更清洁的方法来做到这一点,还是我每次使用它时都必须重新声明它? 另外,如何在我的其他类中初始化配置对象?在我的 1.x 代码中,我会这样做:

final Config config = new Config();

然后开始访问配置对象的属性。现在如何使用类中的所有异步代码对其进行初始化?

这里是今天更新的代码:

import 'package:shared_preferences/shared_preferences.dart';

import '../models/device.dart';

class Config {
  static final Config _config = Config._internal();

  factory Config() => _config;

  final accessTokenKey = 'accessToken';

  String _accessToken = '';

  Future<SharedPreferences> _prefs = SharedPreferences.getInstance();

  Config._internal() {
    print('Config constructor');
    loadData();
  }

  Future<void> loadData() async {
    final SharedPreferences prefs = await _prefs;
    _accessToken = prefs.getString(accessTokenKey) ?? '';
  }

  String get accessToken {
    return _accessToken;
  }

  set accessToken(String accessToken) {
    _accessToken = accessToken;
    _saveString(accessTokenKey, accessToken);
  }

  _saveString(String key, String value, {String printValue = ''}) {
    String printVal = printValue.length > 0 ? printValue : value;
    print('Config: _saveString("$key", "$printVal")');
    final SharedPreferences prefs = await _prefs;
    prefs.setString(key, value);
  }

}

【问题讨论】:

    标签: flutter dart flutter-sharedpreference


    【解决方案1】:

    如果在获取类的实例之前需要等待一些异步工作完成,请考虑使用静态方法(不是factory 构造函数,因为构造函数必须始终返回基类型)。

    您可以在初始化它们之前使用late 字段来允许它们为非空:

    class Config {
    
      late String _accessToken;
      String get accessToken => _accessToken;
    
      Config._();  // private constructor to prevent accidental creation
    
      static Future<Config> create() async {
        final config = Config();
        final preferences = await SharedPreferences.getInstance();
        config._accessToken = await preferences.getString('<your key>');
        return config;
      }
    }
    

    如果您想确保在运行您的应用程序之前对其进行初始化,您可以在调用 runApp() 之前在您的 main() 方法中对其进行初始化,以将控制权交给 Flutter 框架:

    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();  // make sure all plugins loaded etc.
      final config = await Config.create();
      print(config.accessToken);
      runApp(MyApp());
    }
    

    【讨论】:

    • 我对 Dart 类没有太多经验,所以这就是我最终采用工厂方法的原因。但是我不想手动初始化这个类,我希望能够使用构造函数来做到这一点。
    • 不幸的是,构造函数必须返回类的实例(即class Foo的构造函数必须返回Foo,并且永远不能返回Future&lt;Foo&gt;)。您将始终需要在某处使用await。我的答案中的方法显示了如何在创建实例时执行该等待,但更正常的模式是使用异步 getter
    【解决方案2】:

    您可以在init 方法中将SharedPreferences 的实例作为静态字段:

    static SharedPreferences? _prefs; //or: static late SharedPreferences _prefs;
    
    static init() async {
      _prefs = await SharedPreferences.getInstance();
    }
    

    然后调用init() 类似在第一个小部件运行的build() 方法中,一次。现在您可以在任何地方使用_prefs。 如果我想给你展示一个完整的类来使用SharedPreferences,它看起来像这样:

    import 'package:shared_preferences/shared_preferences.dart';
    
    class SharedPreferencesRepository {
      static SharedPreferences? _prefs;
    
      static init() async {
        _prefs = await SharedPreferences.getInstance();
      }
    
      static putInteger(String key, int value) {
        if (_prefs != null) _prefs!.setInt(key, value);
      }
    
      static int getInteger(String key) {
        return _prefs == null ? 0 : _prefs!.getInt(key) ?? 0;
      }
    
      static putString(String key, String value) {
        if (_prefs != null) _prefs!.setString(key, value);
      }
    
      static String getString(String key) {
        return _prefs == null ? 'DEFAULT_VALUE' : _prefs!.getString(key) ?? "";
      }
    
      static putBool(String key, bool value) {
        if (_prefs != null) _prefs!.setBool(key, value);
      }
    
      static bool getBool(String key) {
        return _prefs == null ? false : _prefs!.getBool(key) ?? false;
      }
    }
    

    我希望这对你有用。

    【讨论】:

    • 这是一个单例,我试图避免初始化任何东西 - 使用构造函数代替为我做这件事。
    • 您可以删除所有static 修饰符并获取对象并使用它。最终,此类示例是使用 shared_preferences 的最佳方法之一。
    猜你喜欢
    • 2021-07-25
    • 1970-01-01
    • 2021-04-04
    • 2020-02-28
    • 2014-11-16
    • 2019-08-06
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多