Hive è un archivio NoSQL leggero per Flutter che funziona senza codice nativo. A differenza di SQLite o Firebase, Hive non richiede librerie native e funziona esclusivamente tramite Dart. Secondo Pub.dev, 2024, Hive è stato scaricato oltre 10 milioni di volte ed è utilizzato in un progetto Flutter su tre che necessita di archiviazione locale senza infrastruttura server.
Punti chiave
Hive è un database NoSQL scritto interamente in Dart che non richiede librerie native. È stato creato da Simon Leiter nel 2019 come alternativa a SQLite per progetti Flutter. Hive memorizza i dati in formato binario .hive ottimizzato per lettura e scrittura rapide su dispositivi mobili. Il formato .hive utilizza uno schema di serializzazione personalizzato in cui ogni tipo di dato ha il proprio prefisso di byte, consentendo la lettura del file senza conoscenza preliminare dello schema — a differenza di Protocol Buffers o FlatBuffers.
L'idea centrale di Hive è la massima semplicità. Il database non richiede inizializzazione di motori nativi, non include parser SQL e non utilizza riflessione. Tutte le operazioni sono chiamate dirette a funzioni Dart con serializzazione binaria tramite WriteBuffer e ReadBuffer.
Secondo il sondaggio della Flutter Community (2023), Hive è tra i 5 pacchetti di archiviazione dati più utilizzati in Flutter, secondo solo a shared_preferences in popolarità, ma superandolo per funzionalità e velocità.
Hive utilizza il concetto di Box — analogo a una tabella nei database relazionali. Ogni Box è un file su disco con un insieme di coppie chiave-valore. La chiave può essere int o String, il valore può essere qualsiasi tipo primitivo, lista, Map o un oggetto personalizzato tramite TypeAdapter. I Box sono isolati tra loro e vengono aperti indipendentemente.
Hive non richiede canali di piattaforma. Ciò significa che funziona allo stesso modo su Android, iOS, Web, macOS, Windows e Linux senza configurazione aggiuntiva. Per i progetti destinati alla compilazione web, Hive rimane l'unica soluzione NoSQL leggera — SQLite non funziona nei browser. Hive utilizza IndexedDB come backend per il web, garantendo la persistenza dei dati anche in ambiente browser.
Hive serializza i dati in formato binario durante la scrittura e li deserializza durante la lettura. Il meccanismo interno si basa su BinaryWriter e BinaryReader, che impacchettano i dati in array di byte compatti. La dimensione di archiviazione su disco è in media 2–3 volte inferiore rispetto alla rappresentazione JSON degli stessi dati.
All'apertura di un Box, Hive carica l'intero file in RAM. Ciò offre un'elevata velocità di lettura (microsecondi) ma impone un limite di dimensione: si consiglia di non memorizzare più di 50–100 MB per Box. Per volumi maggiori, utilizzare LazyBox — caricamento lazy dei record dal disco.
Hive funziona single-thread all'interno di un isolato Dart. Le operazioni di scrittura vengono eseguite in modo sincrono con blocco del file. Per l'accesso asincrono, utilizzare Hive.openBox() con await. L'accesso concorrente da più isolati non è supportato direttamente — è necessario un meccanismo di sincronizzazione separato.
Hive occupa una nicchia tra SharedPreferences e SQLite. È più complesso di SharedPreferences (supporta oggetti personalizzati) ma più semplice di SQLite (nessuna query SQL richiesta). Confrontiamo le caratteristiche principali.
| Caratteristica | Hive | SharedPreferences | SQLite |
|---|---|---|---|
| Tipi di dati | Qualsiasi (tramite TypeAdapter) | Solo primitivi | Tipi SQL |
| Velocità di lettura | ~30.000 ops/s | ~5.000 ops/s | ~2.000 ops/s |
| Codice nativo | Non richiesto | Richiesto (Android) | Richiesto |
| Supporto web | Sì | No | No |
| Complessità | Bassa | Minima | Media |
| Reattività | WatchBox | No | Tramite ORM |
Hive è ottimale per piccoli volumi di dati: impostazioni dell'app, cache di risposte API, coda di sincronizzazione locale, preferiti e cronologia di navigazione. Se i dati non superano i 50 MB e non richiedono query relazionali — Hive è più veloce e semplice di SQLite.
Hive non supporta query con filtraggio su più campi, JOIN o funzioni di aggregazione. Se hai bisogno di query complesse come “seleziona tutte le attività di oggi con priorità superiore a 3” — utilizza SQLite con drift o floor. Hive inoltre non è adatto per memorizzare più di 100 MB di dati a causa del caricamento in memoria.
Hive inizia con l'inizializzazione e l'apertura di un Box. Di seguito sono riportate le operazioni di base per uno scenario tipico — memorizzare un elenco di attività in un'applicazione Flutter. Tutti gli esempi funzionano senza chiamate di piattaforma native.
Prima di utilizzare Hive, è necessario chiamare Hive.initFlutter() nella funzione main. Quindi aprire un Box tramite Hive.openBox() — il risultato sarà un'istanza di Box pronta per la lettura e la scrittura.
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 fornisce i metodi put, get, delete e un iteratore per attraversare tutte le voci. Chiavi e valori sono tipizzati tramite generics — per impostazione predefinita Box<dynamic> accetta qualsiasi tipo, ma si consiglia di specificare un tipo concreto.
// Scrivere dati
final box = await Hive.openBox<String>('tasks');
await box.put('task_1', 'Comprare generi alimentari');
// Leggere
final task = box.get('task_1');
// Tutte le chiavi
final allTasks = box.values.toList();
// Eliminare
await box.delete('task_1');
// Svuota Box
await box.clear();
WatchBox è un'estensione di Box che notifica gli abbonati delle modifiche. In Flutter, questo si integra con ValueListenableBuilder: quando qualsiasi valore nel Box cambia, il widget viene ricostruito automaticamente senza chiamare setState.
final watchBox = await Hive.openBox('settings');
// Nel widget
ValueListenableBuilder(
valueListenable: watchBox.listenable(),
builder: (context, box, _) {
final counter = box.get('counter') ?? 0;
return Text('Contatore: $counter');
},
)
TypeAdapter è il meccanismo di Hive per serializzare oggetti Dart personalizzati. L'adattatore descrive come convertire un oggetto in formato binario (write) e viceversa (read). A differenza di json_serializable, TypeAdapter non richiede riflessione ed è più veloce.
L'adattatore implementa l'interfaccia TypeAdapter
// Modello dati
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);
}
}
Per progetti con un gran numero di modelli, Hive fornisce hive_generator e build_runner. L'annotazione @HiveType sulla classe e @HiveField sui campi generano l'adattatore automaticamente. Questo è comodo quando il modello ha 10+ campi — scrivere manualmente read/write diventa noioso.
Hive legge dalla memoria anziché dal disco, offrendo velocità fino a 30.000 operazioni al secondo. Per ottimizzare: apri un Box una volta e riutilizzalo in tutta l'app, non chiamare openBox ripetutamente. Utilizza Hive.box() (getter sincrono) dopo l'inizializzazione — restituisce un Box già aperto senza creare una nuova istanza.
Hive si integra facilmente con i popolari gestori di stato di Flutter. Per Provider, utilizza ChangeNotifierProvider che legge i dati dal Box all'inizializzazione e si aggiorna tramite listenable. Per Riverpod, un StreamProvider sottoscritto a WatchBox funziona bene. Questa combinazione fornisce aggiornamenti reattivi dell'interfaccia a ogni modifica dei dati in Hive senza chiamate manuali a setState. In un tipico progetto Flutter, questa architettura consente di sincronizzare lo stato tra le schermate senza un singleton globale.
Domande frequenti
Hive funziona su Dart puro, quindi può essere utilizzato in qualsiasi progetto Dart: lato server (Dart VM), console o AngularDart. Per Flutter, è necessario aggiungere hive_flutter per l'inizializzazione dei percorsi di archiviazione.
Hive supporta la crittografia AES-256 tramite il parametro encryptionKey all'apertura di un Box. La chiave deve essere una stringa di 32 byte. Un Box crittografato non può essere letto senza la chiave — i dati sono protetti a livello di file.
Isar è il successore di Hive dello stesso autore (Simon Leiter). Isar è più veloce, supporta indici, relazioni e query complesse. Tuttavia, Hive rimane rilevante per scenari semplici dove le capacità relazionali di Isar non sono necessarie, e per progetti dove le dipendenze minime sono importanti.
Hive non ha migrazioni integrate. Se la struttura di TypeAdapter cambia, i vecchi dati non verranno deserializzati. Soluzione: aumentare il typeId dell'adattatore e scrivere una migrazione manuale nel codice, oppure utilizzare delete per la vecchia chiave prima di scriverne una nuova.
Hive carica l'intero Box in memoria. Il limite consigliato è di 50–100 MB per Box. Il superamento può causare ritardi nell'apertura del Box e un aumento del consumo di RAM. Per volumi più grandi, utilizzare più Box o LazyBox con caricamento lazy.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche