Hive est un stockage NoSQL léger pour Flutter qui fonctionne sans code natif. Contrairement à SQLite ou Firebase, Hive ne nécessite pas de bibliothèques natives et fonctionne exclusivement via Dart. Selon Pub.dev, 2024, Hive a été téléchargé plus de 10 millions de fois et est utilisé dans un projet Flutter sur trois nécessitant un stockage local sans infrastructure serveur.
Points clés
Hive est une base de données NoSQL écrite entièrement en Dart qui ne nécessite aucune bibliothèque native. Elle a été créée par Simon Leiter en 2019 comme alternative à SQLite pour les projets Flutter. Hive stocke les données au format binaire .hive optimisé pour une lecture et une écriture rapides sur les appareils mobiles. Le format .hive utilise un schéma de sérialisation personnalisé où chaque type de donnée possède son propre préfixe d'octet, permettant de lire le fichier sans connaissance préalable du schéma — contrairement à Protocol Buffers ou FlatBuffers.
L'idée centrale de Hive est la simplicité maximale. La base de données ne nécessite pas d'initialisation de moteur natif, n'inclut pas d'analyseur SQL et n'utilise pas de réflexion. Toutes les opérations sont des appels directs de fonctions Dart avec sérialisation binaire via WriteBuffer et ReadBuffer.
Selon l'enquête de la Flutter Community (2023), Hive fait partie des 5 packages de stockage de données les plus utilisés dans Flutter, juste derrière shared_preferences en popularité, mais le surpassant en fonctionnalité et en vitesse.
Hive utilise le concept de Box — analogue à une table dans les bases de données relationnelles. Chaque Box est un fichier sur disque contenant un ensemble de paires clé-valeur. La clé peut être int ou String, la valeur peut être n'importe quel type primitif, liste, Map ou un objet personnalisé via TypeAdapter. Les Boxes sont isolés les uns des autres et ouverts indépendamment.
Hive ne nécessite pas de canaux de plateforme. Cela signifie qu'il fonctionne de la même manière sur Android, iOS, Web, macOS, Windows et Linux sans configuration supplémentaire. Pour les projets ciblant la compilation web, Hive reste la seule solution NoSQL légère — SQLite ne fonctionne pas dans les navigateurs. Hive utilise IndexedDB comme backend pour le web, garantissant la persistance des données même dans un environnement de navigateur.
Hive sérialise les données au format binaire lors de l'écriture et les désérialise lors de la lecture. Le mécanisme interne est basé sur BinaryWriter et BinaryReader, qui conditionnent les données en tableaux d'octets compacts. La taille de stockage sur disque est en moyenne 2 à 3 fois inférieure à la représentation JSON des mêmes données.
Lors de l'ouverture d'un Box, Hive charge tout le fichier en RAM. Cela offre une vitesse de lecture élevée (microsecondes) mais impose une limite de taille : il est recommandé de ne pas stocker plus de 50 à 100 Mo par Box. Pour des volumes plus importants, utilisez LazyBox — chargement paresseux des enregistrements depuis le disque.
Hive fonctionne en monothread au sein d'un isolat Dart. Les opérations d'écriture sont effectuées de manière synchrone avec verrouillage de fichier. Pour un accès asynchrone, utilisez Hive.openBox() avec await. L'accès concurrent depuis plusieurs isolats n'est pas pris en charge directement — un mécanisme de synchronisation séparé est nécessaire.
Hive occupe un créneau entre SharedPreferences et SQLite. Il est plus complexe que SharedPreferences (prend en charge les objets personnalisés) mais plus simple que SQLite (pas de requêtes SQL nécessaires). Comparons les principales caractéristiques.
| Caractéristique | Hive | SharedPreferences | SQLite |
|---|---|---|---|
| Types de données | Tout (via TypeAdapter) | Primitifs uniquement | Types SQL |
| Vitesse de lecture | ~30 000 ops/s | ~5 000 ops/s | ~2 000 ops/s |
| Code natif | Non requis | Requis (Android) | Requis |
| Support web | Oui | Non | Non |
| Complexité | Faible | Minimale | Moyenne |
| Réactivité | WatchBox | Non | Via ORM |
Hive est optimal pour les petits volumes de données : paramètres d'application, cache de réponses API, file d'attente de synchronisation locale, favoris et historique de navigation. Si les données ne dépassent pas 50 Mo et ne nécessitent pas de requêtes relationnelles — Hive est plus rapide et plus simple que SQLite.
Hive ne prend pas en charge les requêtes avec filtrage par plusieurs champs, JOIN ou fonctions d'agrégation. Si vous avez besoin de requêtes complexes comme « sélectionner toutes les tâches d'aujourd'hui avec une priorité supérieure à 3 » — utilisez SQLite avec drift ou floor. Hive n'est pas non plus adapté au stockage de plus de 100 Mo de données en raison du chargement en mémoire.
Hive commence par l'initialisation et l'ouverture d'un Box. Voici les opérations de base pour un scénario typique — stocker une liste de tâches dans une application Flutter. Tous les exemples fonctionnent sans appels de plateforme natifs.
Avant d'utiliser Hive, vous devez appeler Hive.initFlutter() dans la fonction main. Ensuite, ouvrez un Box via Hive.openBox() — le résultat sera une instance de Box prête pour la lecture et l'écriture.
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 fournit les méthodes put, get, delete et un itérateur pour parcourir toutes les entrées. Les clés et les valeurs sont typées via des génériques — par défaut Box<dynamic> accepte tout type, mais il est recommandé de spécifier un type concret.
// Écrire des données
final box = await Hive.openBox<String>('tasks');
await box.put('task_1', 'Acheter des courses');
// Lecture
final task = box.get('task_1');
// Toutes les clés
final allTasks = box.values.toList();
// Supprimer
await box.delete('task_1');
// Vider le Box
await box.clear();
WatchBox est une extension de Box qui notifie les abonnés des changements. Dans Flutter, cela s'intègre avec ValueListenableBuilder : lorsque n'importe quelle valeur dans le Box change, le widget est reconstruit automatiquement sans appeler setState.
final watchBox = await Hive.openBox('settings');
// Dans le widget
ValueListenableBuilder(
valueListenable: watchBox.listenable(),
builder: (context, box, _) {
final counter = box.get('counter') ?? 0;
return Text('Compteur : $counter');
},
)
TypeAdapter est le mécanisme de Hive pour sérialiser les objets Dart personnalisés. L'adaptateur décrit comment convertir un objet au format binaire (write) et inversement (read). Contrairement à json_serializable, TypeAdapter ne nécessite pas de réflexion et est plus rapide.
L'adaptateur implémente l'interface TypeAdapter
// Modèle de données
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);
}
}
Pour les projets avec un grand nombre de modèles, Hive fournit hive_generator et build_runner. L'annotation @HiveType sur la classe et @HiveField sur les champs génèrent l'adaptateur automatiquement. C'est pratique lorsque le modèle comporte 10+ champs — l'écriture manuelle de read/write devient fastidieuse.
Hive lit depuis la mémoire plutôt que depuis le disque, offrant des vitesses allant jusqu'à 30 000 opérations par seconde. Pour optimiser : ouvrez un Box une fois et réutilisez-le dans toute l'application, n'appelez pas openBox de manière répétée. Utilisez Hive.box() (getter synchrone) après l'initialisation — il retourne un Box déjà ouvert sans créer une nouvelle instance.
Hive s'intègre facilement avec les gestionnaires d'état populaires de Flutter. Pour Provider, utilisez ChangeNotifierProvider qui lit les données du Box à l'initialisation et se met à jour via listenable. Pour Riverpod, un StreamProvider abonné à WatchBox fonctionne bien. Cette combinaison fournit des mises à jour réactives de l'UI à chaque changement de données dans Hive sans appels manuels de setState. Dans un projet Flutter typique, cette architecture permet de synchroniser l'état entre les écrans sans singleton global.
Questions fréquentes
Hive fonctionne sur du Dart pur, donc il peut être utilisé dans n'importe quel projet Dart : serveur (Dart VM), console ou AngularDart. Pour Flutter, hive_flutter est nécessaire en plus pour l'initialisation des chemins de stockage.
Hive prend en charge le chiffrement AES-256 via le paramètre encryptionKey lors de l'ouverture d'un Box. La clé doit être une chaîne de 32 octets. Un Box chiffré ne peut pas être lu sans la clé — les données sont protégées au niveau du fichier.
Isar est le successeur de Hive du même auteur (Simon Leiter). Isar est plus rapide, prend en charge les index, les relations et les requêtes complexes. Cependant, Hive reste pertinent pour les scénarios simples où les capacités relationnelles d'Isar ne sont pas nécessaires, et pour les projets où les dépendances minimales sont importantes.
Hive n'a pas de migrations intégrées. Si la structure du TypeAdapter change, les anciennes données ne seront pas désérialisées. Solution : augmentez le typeId de l'adaptateur et écrivez une migration manuelle dans le code, ou utilisez delete pour l'ancienne clé avant d'en écrire une nouvelle.
Hive charge le Box entièrement en mémoire. La limite recommandée est de 50 à 100 Mo par Box. Le dépassement peut entraîner des délais lors de l'ouverture du Box et une augmentation de la consommation de RAM. Pour des volumes plus importants, utilisez plusieurs Boxes ou LazyBox avec chargement paresseux.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi