ObjectBox è un database NoSQL ad alte prestazioni ottimizzato per dispositivi mobili e edge. A differenza di SQLite, utilizza un proprio formato di archiviazione a file piatti senza livello SQL. Secondo ObjectBox Benchmarks, 2024, ObjectBox esegue operazioni di inserimento e lettura da 10 a 100 volte più velocemente di SQLite su dispositivi Android, rendendolo la scelta migliore per applicazioni mobili ad alto carico.
Punti chiave
ObjectBox è un database NoSQL in-memory sviluppato dall'azienda tedesca ObjectBox.io. A differenza dei database relazionali tradizionali, ObjectBox memorizza gli oggetti direttamente in file piatti utilizzando il proprio formato SLOT (Super Lightweight Object Tree). Ciò elimina il sovraccarico di ORM e analisi SQL. Il formato SLOT è ottimizzato per dispositivi con memoria limitata: i dati vengono deframmentati automaticamente e la dimensione del DB è in media da 4 a 6 volte inferiore a un database SQLite equivalente con lo stesso numero di record.
ObjectBox supporta tutte le principali piattaforme mobili: Android, iOS e Flutter. Per Android, la generazione del codice è disponibile tramite il ObjectBox Gradle Plugin, che elabora le entità annotate e crea classi Box per lavorare con i dati. Per Flutter viene utilizzato un plugin nativo con wrapper Dart. Oltre alle piattaforme mobili, ObjectBox funziona su Linux, macOS, Windows e WebAssembly, consentendo di riutilizzare il modello di dati tra l'app mobile e la sincronizzazione del server.
Secondo uno studio di ObjectBox (2023), il database è utilizzato in oltre 5.000 applicazioni su Google Play, incluse app con oltre 10 milioni di utenti. Casi d'uso principali: caching dei dati, funzionamento offline e archiviazione di serie temporali (IoT). ObjectBox è particolarmente popolare nelle app di monitoraggio della salute e fitness che richiedono una registrazione rapida delle letture dei sensori sul dispositivo senza connessione Internet costante e per raccogliere analisi da più dispositivi.
ObjectBox è nato come alternativa a Realm e SQLite per la piattaforma Android. La prima versione stabile è stata rilasciata nel 2018. La differenza principale rispetto a Realm è che ObjectBox non ha restrizioni GPL (utilizza Apache 2.0) e supporta più piattaforme: dai dispositivi mobili ai server Linux.
ObjectBox fornisce: generazione automatica di classi Box, indici integrati per ricerche rapide, transazioni con supporto rollback, query reattive tramite RxJava e Kotlin Flow e sincronizzazione tra dispositivi tramite ObjectBox Sync (protocollo proprietario). A differenza di Firebase Realtime Database, ObjectBox Sync funziona con un modello peer-to-peer senza server centrale, riducendo la latenza e i costi dell'infrastruttura.
ObjectBox memorizza i dati nel proprio formato binario .mdb (ObjectBox Data File). Ogni entità viene mappata su un file, dove i record vengono archiviati in sequenza con un offset fisso. Ciò consente di leggere e scrivere singoli oggetti senza scansionare l'intero file.
Lavorare con ObjectBox non richiede SQL: le query vengono costruite tramite un'API fluida nel codice. Il compilatore genera classi helper MyObjectBox e Boxes che incapsulano tutte le operazioni CRUD. Il modello di dati viene descritto tramite annotazioni @Entity, @Id, @Index e @Relation.
// Connecting ObjectBox in Android
class App: Application() {
lateinit var boxStore: BoxStore
override fun onCreate() {
super.onCreate()
boxStore = MyObjectBox.builder()
.androidContext(this)
.build()
}
}
Secondo i benchmark ufficiali, ObjectBox supera significativamente SQLite in velocità, soprattutto nelle inserzioni batch e nelle letture di massa. Tuttavia, SQLite rimane lo standard de facto per le applicazioni mobili grazie alla sua diffusione e al supporto SQL integrato.
| Operazione | ObjectBox | SQLite | Differenza |
|---|---|---|---|
| Inserimento (1000 record) | ~5 ms | ~180 ms | ×36 più veloce |
| Lettura (1000 record) | ~3 ms | ~70 ms | ×23 più veloce |
| Aggiornamento (1000 record) | ~6 ms | ~150 ms | ×25 più veloce |
| Ricerca per indice | ~0.1 ms | ~2 ms | ×20 più veloce |
| Dimensione DB (1000 oggetti) | ~28 KB | ~112 KB | 4 volte più piccolo |
ObjectBox è inferiore a SQLite in scenari che richiedono query JOIN complesse, funzioni di aggregazione (SUM, COUNT con raggruppamento) o integrazione con uno schema SQL esistente. Se il progetto utilizza già SQLite con Room ORM, la migrazione a ObjectBox richiederà la riscrittura di tutta la logica di accesso ai dati. ObjectBox inoltre non supporta query SQL personalizzate — solo API fluida. Tuttavia, per le tipiche operazioni CRUD e la memorizzazione nella cache, ObjectBox fornisce un miglioramento delle prestazioni fino a 100 volte, come confermato dai benchmark ufficiali su dispositivi Android con diverse versioni del sistema operativo.
ObjectBox utilizza annotazioni per definire le entità. Dopo la compilazione, vengono create classi Box con metodi put, get, remove e query. Di seguito sono riportate le operazioni tipiche per un modello Task in un'applicazione di elenco attività.
Ogni entità è annotata con @Entity. Un campo con @Id diventa la chiave primaria e @Index accelera le ricerche su quel campo. ObjectBox supporta la generazione automatica dell'ID quando il valore è 0.
@Entity
data class Task(
@Id var id: Long = 0,
@Index var title: String = "",
var isCompleted: Boolean = false,
var priority: Int = 0
)
Box è la classe principale per lavorare con le entità. Il metodo put() salva o aggiorna un oggetto, get() legge per ID e remove() elimina. Tutte le operazioni di base sono sincrone e vengono eseguite sul thread chiamante.
val taskBox: Box<Task> = boxStore.boxFor(Task::class.java)
// Create
val task = Task(title = "Buy products", priority = 3)
val newId = taskBox.put(task)
// Read
val savedTask = taskBox.get(newId)
// Update
savedTask.isCompleted = true
taskBox.put(savedTask)
// Delete
taskBox.remove(newId)
ObjectBox supporta query reattive tramite .subscribe(). L'abbonato riceve notifiche quando i dati corrispondenti alla condizione della query cambiano. Ciò è comodo per l'interfaccia utente che aggiorna automaticamente l'elenco quando gli elementi vengono aggiunti o rimossi.
val query = taskBox.query()
.equal(Task_.isCompleted, false)
.orderDesc(Task_.priority)
.build()
query.subscribe { tasks ->
// tasks — List, si aggiorna automaticamente
updateUi(tasks)
}
ObjectBox supporta relazioni tra entità — Uno-a-Uno, Uno-a-Molti e Molti-a-Molti. Le relazioni sono definite tramite l'annotazione @Relation. A differenza di SQLite, ObjectBox non utilizza chiavi esterne: le relazioni sono implementate tramite elenchi di ID in file piatti, accelerando la navigazione nel grafo degli oggetti.
La relazione @Backlink consente di passare da un'entità figlia al suo genitore senza un campo di riferimento separato. ObjectBox mantiene automaticamente il backlink, eliminando la duplicazione dei dati e la sincronizzazione tra due tabelle.
ObjectBox Query Builder consente di creare catene di condizioni: equal, notEqual, greater, less, in, contains, startsWith. Tutte le condizioni possono essere combinate tramite and/or. Il risultato può essere ordinato, limitato e ottenuto come List o LazyList (per set di dati di grandi dimensioni).
ObjectBox indicizza automaticamente il campo @Id. Per indici personalizzati, utilizzare l'annotazione @Index sui campi interrogati frequentemente. Gli indici accelerano le query equal e in ma rallentano le inserzioni — non indicizzare campi che non vengono cercati. ObjectBox supporta indici compositi per filtrare contemporaneamente su più campi. Gli indici compositi sono particolarmente utili per i filtri di elenco: ad esempio, la ricerca di attività incomplete con priorità alta è decine di volte più veloce con un indice composito sui campi isCompleted e priority.
ObjectBox Sync è una tecnologia proprietaria per la sincronizzazione dei dati in tempo reale tra dispositivi. Utilizza un protocollo basato su WebSocket con risoluzione dei conflitti tramite last-writer-wins. Sync è adatto per app che necessitano di sincronizzazione offline: note, elenchi di attività, dati IoT da più sensori. Tuttavia, per la produzione è necessario l'acquisto di una licenza.
// Query with multiple conditions
val highPriorityIncomplete = taskBox.query()
.greater(Task_.priority, 5)
.equal(Task_.isCompleted, false)
.build()
.find()
// Substring search
val searchResults = taskBox.query()
.contains(Task_.title, "product", StringOrder.CASE_INSENSITIVE)
.build()
.find()
Domande frequenti
ObjectBox è distribuito con licenza Apache 2.0, che ne consente l'uso commerciale senza restrizioni. La funzione ObjectBox Sync (sincronizzazione multipiattaforma) è proprietaria e richiede l'acquisto di una licenza per la produzione.
BoxStore è thread-safe: più thread possono leggere i dati contemporaneamente. Le scritture vengono bloccate a livello di Box. Per transazioni complesse, utilizzare boxStore.runInTx(), che garantisce l'atomicità di un gruppo di operazioni.
Sì, ObjectBox supporta Kotlin Multiplatform (KMP) a partire dalla versione 3.0. I target disponibili sono Android, iOS, JVM e Native. Per KMP viene utilizzato un plugin Gradle separato objectbox-kotlin con supporto expect/actual.
ObjectBox memorizza i dati in file .mdb nella directory dell'app. Per il backup, copiare l'intera directory ObjectBox tramite BoxStore.copy() o copiare manualmente i file dopo aver chiamato boxStore.close(). I file live non possono essere copiati — ciò danneggerebbe i dati.
Room è un ORM basato su SQLite, richiede query SQL e ha un sovraccarico di mappatura degli oggetti. ObjectBox è un database NoSQL senza SQL, un ordine di grandezza più veloce, ma non supporta JOIN complessi e non è un database relazionale. La scelta dipende dall'attività: per dati relazionali — Room, per archiviazione rapida di oggetti — ObjectBox.
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