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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також