Как добавить Isar в проект на Flutter

Первое время при работе с Flutter мне хватало Hive. Быстро, удобно, но возможностей Hive мне стало не хватать. На странице https://pub.dev/packages/hive разработчики посоветовали попробовать Isar и я решила рискнуть. Много звездочек, но он совсем свежий, ошибки не гуглятся, а документация оставляет большие белые пятна.

Я не хочу дублировать тут все шаги, вот тут можно все посмотреть. Скачали -> Создали схему -> Запустили генератор. Четвертый шаг тоже простой, только схему (schemas) нужно взять из сгенерированного файла. У меня это activity.g.dart. Сразу в этом файле можно посмотреть как называется список ваших объектов.

Я немного затормозила тут и долго не могла понять почему у меня ничего не работает. Оказывается я по правилам английского языка искала activities, а вот генератор создал activitys. Наверное можно как-то его настроить, но я не успела пока так глубоко капнуть, если знаете как его заставить правильно писать автоматически, расскажите мне)

Ну вот и все что есть в быстром старте. Но мне же нужно следить за изменениями, закрыть потом все и конечно следить за уже открытыми экземплярами и не открывать повторно. Вот об этом я и хотела Вам рассказать)

Для того что бы контролировать все из одно места я создам IzarManager, в единственном экземпляреstatic final IzarManager instance = IzarManager._(); IzarManager._();

Теперь мне нужно посчитать, сколько раз я его открыла и закрыла. В дальнейшем у меня будут еще сущности для хранения, поэтому я буду считать каждую отдельно, по имени final Map<String, int> _izarCounter = <String, int>{};

Создадим дженерик функцию для открытия базы данных. Сначала проверяем открыта ли она, если да добавляем в счетчик, если нет открываем.

  Future<Isar> _openIsar<T>(String name, CollectionSchema<T> schema) async {
    final dir = await getApplicationSupportDirectory();
    final izar = Isar.getInstance(name);

    if (izar != null && izar.isOpen) {
      final count = _izarCounter[name] ?? 1;
      _izarCounter[name] = count + 1;
      return izar;
    }

    _izarCounter[name] = 1;

    return Isar.open(
      schemas: [schema],
      directory: dir.path,
      name: name,
      inspector: true,
    );
  }

При закрытии точно так же проверяем нужно ли закрыть или обновить счет.

  Future<void> closeIsar<T>(Isar izar) async {
    if (!izar.isOpen) {
      _izarCounter.remove(izar.name);
      return;
    }

    var count = _izarCounter[izar.name] ?? 1;
    count -= 1;
    _izarCounter[izar.name] = count;
    if (count > 0) return;

    await izar.close();
  }

ну и сам вызов открытия выглядит так

  Future<Isar> openActivityDB() async {
    return _openIsar('activities', ActivitySchema);
  }

Вот так выглядит код для записи в базу данных. Открыли, записали, закрыли.

  Future<void> saveInDatabase(activity) async {
    final isar = await IzarManager.instance.openActivityDB();

    await isar.writeTxn((isar) async {
      await isar.activities.put(activity); // insert & update
    });
    await IzarManager.instance.closeIsar(isar);
  }

Но вот с чтением все немного сложнее, потому что у меня данные могут обновиться без перерисовки. Мне нужно открыть базу данных и подписаться на изменения и только потом закрыть.

class ActivitiesWidgetModel extends ChangeNotifier {
  var _activities = <Activity>[];
  StreamSubscription<void>? streamSubscription;

  Future<void> _readActivitiesFromIsar() async {
      _activities = await (await _isar).activities.where().findAll();

      notifyListeners();
    }

    void _setup() async {
      _isar = IzarManager.instance.openActivityDB();
      await _readActivitiesFromIsar();

      Stream<void> userChanged = (await _isar).activities.watchLazy();
      streamSubscription = userChanged.listen((newResult) {
        _readActivitiesFromIsar();
      });
    }
}

watchLazy помогает нам следить за изменениями и подписаться на стрим. Ну и конечно при уходе со страницы мы должны закрыть все и отписаться от прослушки.

  @override
  void dispose() async {
    streamSubscription?.cancel();
    await IzarManager.instance.closeIsar((await _isar));
    super.dispose();
  }

Пока мне кажется что Isar это действительно просто, работает быстро, много фильтров и легко искать данные. Пока столкнулась только с проблемой параллельного использования нескольких баз данных, но все решаемо. Если возникнут вопросы по коду то рекомендую посетить канал LazyLoad Dart & Flutter на ютубе. Очень детальный и полезный курс, мне очень помог стартовать во flutter. Надеюсь Вам пригодится мой туториал, спасибо за внимание!

Want to improve your IT-english skills and have fun?
Follow GeekEng in telegram
Learn