使用 Provider 将 Map 的状态保存到 Flutter 应用

Posted

技术标签:

【中文标题】使用 Provider 将 Map 的状态保存到 Flutter 应用【英文标题】:Saving state of Map to Flutter app with Provider 【发布时间】:2021-02-25 09:53:36 【问题描述】:

我有一个基于以下结构呈现的 ListView。该地图有大约 5 个“字符串”键值,每个都有 1 个 10-15 个项目模型的列表。 isDone 通过使用 toggleDone() 调用各个 ItemModel 来翻转。这会将布尔状态保存在应用程序中,但一旦应用程序关闭,它就会重置。我查看了共享首选项,但是 -

    我不知道如何编码这个特定的地图,然后加载必要的值。 这是我应该在 Model 类上做的事情吗? 还是单独的 ItemModel 类? 有没有办法只对 bool 值进行编码然后加载这些值?

保存 Map 的 ChangeNotifier 类:

 ```
class Data extends ChangeNotifier 
   List<ItemModel> getData(name) => items[name];

        Map<String, List<ItemModel>> items = 
                'String': [
                  ItemModel(
                    title: 'Some text',
                    text:
                        'Some other text',
                    isDone: false,
                    duration: Duration(
                      hours: 0,
                      minutes: 0,
                      seconds: 10,
                    ),
                  ),
                ]
            ;
          

ItemModel:

class ItemModel 
  final String title;
  final String text;
  bool isDone;
  Duration duration;

  ItemModel(
      this.text, this.title, this.isDone = false, this.duration);

  void toggleDone() 
    isDone = !isDone;
  

对于 List 中的每个 ItemModel,都会呈现一个如下所示的 Item。它需要 isDone 的 ItemModel 值来设置 isChecked 属性。

class Item extends StatelessWidget 
  final String title;
  final String text;
  final bool isChecked;
  final Function checkboxCallback;

  Item(
      this.text,
      this.title,
      this.isChecked,
      this.checkboxCallback);

      @override
      Widget build(BuildContext context) 
        return Padding(
          child: ListTile(
            leading: Checkbox(
              value: isChecked,
              onChanged: checkboxCallback,
            ),
            title: Text(
              title,
            ),
            subtitle: isChecked
                ? Text('')
                : Text(
                    text,
                  ),
          ),
        );
      
    

感谢您的帮助????

【问题讨论】:

【参考方案1】:

正如您提到的,SharedPreferences 仅支持持久的原始值。假设您可以保证列表中 ItemModel 的每个实例的唯一键,您可以做的是围绕 SharedPreferences 编写自己的包装器:

import 'package:shared_preferences/shared_preferences.dart';

abstract class SharedPreferencesKeys 
  static const title = 'title';
  static const text = 'text';
  static const isDone = 'isDone';
  static const duration = 'duration';


class SharedPreferencesImpl 
  SharedPreferences _preferences;
  Future<SharedPreferences> get preferences async => _preferences ??= await SharedPreferences.getInstance();

  Future<void> write(String key, ItemModel value) async 
    final sharedPrefs = await preferences;
    await sharedPrefs.setString('$key_$SharedPreferencesKeys.title', value.title);
    await sharedPrefs.setString('$key_$SharedPreferencesKeys.text', value.text);
    await sharedPrefs.setBool('$key_$SharedPreferencesKeys.isDone', value.isDone);
    await sharedPrefs.setInt('$key_$SharedPreferencesKeys.duration', value.duration.microseconds);
  

  Future<ItemModel> read(String key) async 
    final sharedPrefs = await preferences;
    final title = await sharedPrefs.getString('$key_$SharedPreferencesKeys.title');
    final text = await sharedPrefs.getString('$key_$SharedPreferencesKeys.text');
    final isDone = await sharedPrefs.getBool('$key_$SharedPreferencesKeys.isDone');
    final microseconds = await sharedPrefs.getInt('$key_$SharedPreferencesKeys.duration');
    return ItemModel(
      title: title,
      text: text,
      isDone: isDone,
      duration: Duration(microseconds: microseconds),
    );
  

  Future<void> delete(String key) async 
    final sharedPrefs = await preferences;
    await sharedPrefs.remove('$key_$SharedPreferencesKeys.title');
    await sharedPrefs.remove('$key_$SharedPreferencesKeys.text');
    await sharedPrefs.remove('$key_$SharedPreferencesKeys.isDone');
    await sharedPrefs.remove('$key_$SharedPreferencesKeys.duration');
  

【讨论】:

谢谢,我会试试这个!你知道为什么我得到错误“'await'应用于'int',这不是'Future'。”?您对实例化 SharedPreferencesImpl 类的最佳位置有意见吗? 我需要查看您的代码,显然您调用了一个错误的函数,该函数返回 int 而不是 Future&lt;bool&gt; 但我不能不看就告诉您是哪一个。至于实例化的地方取决于你的架构。如果您刚开始使用 Flutter,请查看 BLoC 模式。另外,请查看 providerriverpod 依赖注入包。

以上是关于使用 Provider 将 Map 的状态保存到 Flutter 应用的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 中 PageController 的 Provider 状态管理

Flutter:如何用 Provider 播放动画?

自定义状态管理Provider以及原理分析

自定义状态管理Provider以及原理分析

颤振:如何将对象注册到具有名称的提供者并按名称获取

使 API 在所有小部件中都可访问 - 使用已实例化变量的 Provider?