Hive — леко NoSQL хранилище за Flutter, което работи без нативен код. За разлика от SQLite или Firebase, Hive не изисква свързване на нативни библиотеки и работи изключително чрез Dart. Според Pub.dev, 2024, Hive е изтеглен над 10 милиона пъти и се използва във всеки трети Flutter проект, който изисква локално съхранение на данни без сървърна инфраструктура.
Основни точки
Hive — е NoSQL база данни, написана изцяло на Dart, която не изисква нативни библиотеки. Създадена е от Simon Leiter през 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 без допълнителна конфигурация. За проекти, насочени към уеб компилация, Hive остава единственото леко NoSQL решение — SQLite не работи в браузъра. В същото време Hive използва IndexedDB като backend за уеб, което осигурява устойчивост на данните и в браузърна среда.
Hive сериализира данни в двоичен формат при запис и десериализира при четене. Вътрешният механизъм се основава на BinaryWriter и BinaryReader, които опаковат данните в компактни байтови масиви. Размерът на хранилището на диска е средно 2–3 пъти по-малък от JSON представянето на същите данни.
При отваряне на Box, Hive зарежда целия файл в RAM. Това осигурява висока скорост на четене (микросекунди), но налага ограничение върху размера на данните: препоръчва се съхраняване на не повече от 50–100 MB на един 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) | Необходим |
| Уеб поддръжка | Да | Не | Не |
| Сложност | Ниска | Минимална | Средна |
| Реактивност | WatchBox | Не | Чрез ORM |
Hive е оптимален за малки обеми данни: настройки на приложение, кеш на API отговори, локална опашка за синхронизация, любими и история на разглеждане. Ако данните не надвишават 50 MB и не изискват релационни заявки — Hive е по-бърз и по-прост от SQLite.
Hive не поддържа заявки с филтриране по множество полета, JOIN, агрегатни функции. Ако имате нужда от сложни заявки като “избери всички задачи за днес с приоритет над 3” — използвайте SQLite с drift или floor. Hive също не е подходящ за съхранение на над 100 MB данни поради зареждане в паметта.
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 и съдържа итератор за обхождане на всички записи. Ключовете и стойностите се типизират чрез generics — по подразбиране 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, widget-ът се преизгражда автоматично без извикване на setState.
final watchBox = await Hive.openBox('settings');
// В widget-а
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() (синхронен getter) след инициализация — връща вече отворен Box без създаване на нова инстанция.
Hive лесно се интегрира с популярните Flutter мениджъри на състояние. За Provider използвайте ChangeNotifierProvider, който чете данни от Box при инициализация и се актуализира чрез listenable. За Riverpod е подходящ StreamProvider, абониран за WatchBox. Такава комбинация осигурява реактивни актуализации на UI при всяка промяна на данни в Hive без ръчно извикване на setState. В типичен Flutter проект такава архитектура позволява синхронизиране на състоянието между екраните без глобален singleton.
Често задавани въпроси
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 MB на един Box. При превишаване са възможни закъснения при отваряне на Box и повишена консумация на RAM. За по-големи обеми използвайте множество Box-ове или LazyBox с мързеливо зареждане.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също