Hive — лёгкое NoSQL хранилище для Flutter, работающее без нативного кода. В отличие от SQLite или Firebase, Hive не требует подключения нативных библиотек и работает исключительно через Dart. По данным Pub.dev, 2024, Hive загружается более 10 миллионов раз и используется в каждом третьем Flutter-проекте, где требуется локальное хранение данных без серверной инфраструктуры.
Главное
Hive — это NoSQL база данных, написанная целиком на Dart и не требующая нативных библиотек. Она создана Симоном Лейтером в 2019 году как альтернатива SQLite для Flutter-проектов. Hive хранит данные в бинарном формате .hive, который оптимизирован для быстрого чтения и записи на мобильных устройствах. Формат .hive использует кастомную схему сериализации, при которой каждый тип данных имеет свой байтовый префикс, что позволяет читать файл без предварительного знания схемы — в отличие от Protocol Buffers или FlatBuffers.
Основная идея Hive — максимальная простота. База данных не требует инициализации нативных движков, не включает SQL-парсер и не использует рефлексию. Все операции — это прямые вызовы Dart-функций с бинарной сериализацией через WriteBuffer и ReadBuffer.
По данным опроса Flutter Community (2023), Hive входит в топ-5 самых используемых пакетов для хранения данных во Flutter, уступая только shared_preferences по популярности, но превосходя его по функциональности и скорости.
Hive использует концепцию Box — аналога таблицы в реляционных БД. Каждый Box — это файл на диске с набором пар ключ-значение. Ключом может быть int или String, значением — любой примитивный тип, список, Map или кастомный объект через TypeAdapter. Box-ы изолированы друг от друга и открываются независимо.
Hive не требует платформенных каналов (platform channels). Это значит, что он работает одинаково на Android, iOS, Web, macOS, Windows и Linux без дополнительной настройки. Для проектов, нацеленных на web-сборку, Hive остаётся единственным лёгким NoSQL-решением — SQLite в браузере не работает. При этом Hive использует IndexedDB в качестве бэкенда для web, что обеспечивает персистентность данных и в браузерном окружении.
Hive сериализует данные в бинарный формат при записи и десериализует при чтении. Внутренний механизм основан на BinaryWriter и BinaryReader, которые упаковывают данные в компактные байтовые массивы. Размер хранилища на диске в среднем в 2–3 раза меньше, чем JSON-представление тех же данных.
При открытии Box Hive загружает весь файл в оперативную память. Это обеспечивает высокую скорость чтения (микросекунды), но накладывает ограничение на размер данных: рекомендуется хранить в Hive не более 50–100 МБ на один Box. Для больших объёмов используйте LazyBox — ленивую загрузку записей с диска.
Hive работает однопоточно в изоляции Dart-изолята. Операции записи выполняются синхронно с блокировкой файла. Для асинхронного доступа используйте Hive.openBox() с await. Конкурентный доступ из нескольких изолятов не поддерживается напрямую — для этого нужен отдельный механизм синхронизации.
Hive занимает нишу между SharedPreferences и SQLite. Он сложнее, чем SharedPreferences (поддерживает кастомные объекты), но проще, чем SQLite (не требует SQL-запросов). Сравним ключевые характеристики.
| Характеристика | Hive | SharedPreferences | SQLite |
|---|---|---|---|
| Типы данных | Любые (через TypeAdapter) | Только примитивы | SQL-типы |
| Скорость чтения | ~30 000 ops/s | ~5 000 ops/s | ~2 000 ops/s |
| Нативный код | Не требуется | Требуется (Android) | Требуется |
| Web support | Да | Нет | Нет |
| Сложность | Низкая | Минимальная | Средняя |
| Реактивность | WatchBox | Нет | Через ORM |
Hive оптимален для небольших объёмов данных: настроек приложения, кэша ответов API, локальной очереди синхронизации, избранного и истории просмотров. Если данные не превышают 50 МБ и не требуют реляционных запросов — Hive быстрее и проще SQLite.
Hive не поддерживает запросы с фильтрацией по нескольким полям, JOIN, агрегатные функции. Если нужно делать сложные запросы типа «выбрать все задачи за сегодня с приоритетом выше 3» — используйте SQLite с drift или floor. Hive также не подходит для хранения более 100 МБ данных из-за загрузки в память.
Hive начинает работу с инициализации и открытия Box. Ниже приведены базовые операции для типового сценария — хранения списка задач в Flutter-приложении. Все примеры работают без нативных платформенных вызовов.
Перед использованием Hive необходимо вызвать Hive.initFlutter() в main-функции. Затем открыть Box через Hive.openBox() — результатом будет экземпляр Box, готовый к чтению и записи.
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void async main() {
await Hive.initFlutter();
final settingsBox = await Hive.openBox('settings');
runApp(MyApp());
}
Box предоставляет методы put, get, delete и содержит итератор для обхода всех записей. Ключи и значения типизируются через дженерики — по умолчанию Box<dynamic> допускает любые типы, но рекомендуется указывать конкретный тип.
// Запись данных
final box = await Hive.openBox<String>('tasks');
await box.put('task_1', 'Купить продукты');
// Чтение
final task = box.get('task_1');
// Все ключи
final allTasks = box.values.toList();
// Удаление
await box.delete('task_1');
// Очистка Box
await box.clear();
WatchBox — расширение Box, которое уведомляет подписчиков об изменениях. В Flutter это интегрируется с ValueListenableBuilder: при изменении любого значения в Box виджет перестраивается автоматически, без вызова setState.
final watchBox = await Hive.openBox('settings');
// В виджете
ValueListenableBuilder(
valueListenable: watchBox.listenable(),
builder: (context, box, _) {
final counter = box.get('counter') ?? 0;
return Text('Счётчик: $counter');
},
)
TypeAdapter — механизм Hive для сериализации кастомных Dart-объектов. Адаптер описывает, как преобразовать объект в бинарный формат (write) и обратно (read). В отличие от json_serializable, TypeAdapter не требует рефлексии и работает быстрее.
Адаптер реализует интерфейс TypeAdapter
// Модель данных
class Task {
final String title;
final bool isCompleted;
Task({required this.title, this.isCompleted = false});
}
// TypeAdapter
class TaskAdapter extends TypeAdapter<Task> {
@override
final int typeId = 0;
@override
Task read(BinaryReader reader) {
return Task(
title: reader.readString(),
isCompleted: reader.readBool(),
);
}
@override
void write(BinaryWriter writer, Task obj) {
writer.writeString(obj.title);
writer.writeBool(obj.isCompleted);
}
}
Для проектов с большим количеством моделей Hive предоставляет hive_generator и build_runner. Аннотация @HiveType на классе и @HiveField на полях генерирует адаптер автоматически. Это удобно, когда модель содержит 10+ полей — ручное написание read/write становится трудоёмким.
Hive выполняет чтение из памяти, а не с диска, что даёт скорость до 30 000 операций в секунду. Для оптимизации: открывайте Box один раз и переиспользуйте его во всём приложении, не вызывайте openBox повторно. Используйте Hive.box() (синхронный геттер) после инициализации — он возвращает уже открытый Box без создания нового экземпляра.
Hive легко интегрируется с популярными state-менеджерами Flutter. Для Provider используйте ChangeNotifierProvider, который читает данные из Box при инициализации и обновляется через listenable. Для Riverpod подойдёт StreamProvider, подписанный на WatchBox. Такая связка даёт реактивное обновление UI при каждом изменении данных в Hive без ручного вызова setState. В типовом проекте Flutter такая архитектура позволяет синхронизировать состояние между экранами без глобального синглтона.
Часто задаваемые вопросы
Hive работает на чистом Dart, поэтому его можно использовать в любом Dart-проекте: серверном (Dart VM), консольном или в AngularDart. Для Flutter дополнительно подключается hive_flutter с инициализацией путей хранения.
Hive поддерживает AES-256 шифрование через параметр encryptionKey при открытии Box. Ключ должен быть 32-байтовой строкой. Зашифрованный Box нельзя прочитать без ключа — данные защищены на уровне файла.
Isar — преемник Hive от того же автора (Simon Leiter). Isar быстрее, поддерживает индексы, связи и сложные запросы. Однако Hive остаётся актуальным для простых сценариев, где не нужны реляционные возможности Isar, и для проектов, где важна минимальная зависимость.
Hive не имеет встроенных миграций. Если структура TypeAdapter изменилась, старые данные не десериализуются. Решение: увеличить typeId адаптера и написать ручную миграцию в коде, либо использовать delete для старого ключа перед записью нового.
Hive загружает Box в память целиком. Рекомендуемый лимит — 50–100 МБ на один Box. При превышении возможны задержки при открытии Box и повышенное потребление RAM. Для больших объёмов используйте несколько Box-ов или LazyBox с ленивой загрузкой.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также