Сохранение состояния карты в приложении Flutter с поставщиком

#flutter #dart

#flutter #dart

Вопрос:

У меня есть ListView, который отображается на основе приведенной ниже структуры. Карта имеет около 5 «строковых» ключевых значений, каждое из которых содержит 1 список из 10-15 моделей элементов. isDone переключается путем вызова отдельных ItemModels с помощью toggleDone() . Это сохраняет состояние bool в приложении, но оно сбрасывается после закрытия приложения. Я изучил sharedprefences, но —

  1. Я не могу понять, как закодировать эту конкретную карту, а затем загрузить необходимые значения.
  2. Это даже то, что я должен делать в классе Model или отдельных классах ItemModel?
  3. Есть ли способ кодировать только значения bool, а затем загружать их?

Класс 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;
  }
}
  

Для каждой ItemModel в списке отображается элемент, который выглядит следующим образом. Для установки свойства IsChecked требуется значение ItemModel isDone.

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

Комментарии:

1. Спасибо, я попробую это! Знаете ли вы, почему я получаю сообщение об ошибке «‘await’ применяется к ‘int’, которое не является ‘Future’.»? И есть ли у вас мнение о том, где лучше всего создать экземпляр класса SharedPreferencesImpl?

2. Мне нужно было бы увидеть ваш код, по-видимому, вы вызываете неправильную функцию, которая возвращает int вместо Future<bool> , но я не могу сказать вам, какой из них, не посмотрев. Что касается места для создания экземпляра, это зависит от вашей архитектуры. Если вы только начинаете с Flutter, взгляните на шаблон блоков. Кроме того, взгляните на provider и riverpod пакеты для внедрения зависимостей.