Integración de Real en Android: Dependencias y Objetos de Datos
Clase 7 de 19 • Curso de Android: Modo Offline con Room y Realm
Resumen
La integración de bases de datos en aplicaciones Android es fundamental para crear experiencias de usuario robustas y funcionales. En este artículo, exploraremos cómo implementar Realm, una potente alternativa a Room, para gestionar datos locales en aplicaciones Kotlin. Aprenderás las diferencias clave entre ambas tecnologías y cómo configurar correctamente los objetos y consultas en Realm.
¿Cómo configurar Realm en un proyecto Android?
Antes de comenzar a utilizar Realm en nuestro proyecto, necesitamos agregar las dependencias necesarias. Este proceso es similar a la configuración de Room, pero con algunas diferencias importantes.
Agregando las dependencias de Realm
Para integrar Realm en nuestro proyecto Android, debemos seguir estos pasos:
-
Agregar la versión de Realm en el archivo de configuración:
// Debajo de Room // Versión 2.1.0 - compatible con Kotlin 2.0
-
Incluir el plugin de Realm para Kotlin:
// En la sección de plugins id 'io.realm.kotlin'
-
Agregar las dependencias en el módulo de la aplicación:
// Implementación de Realm implementation 'io.realm.kotlin:library-base:2.1.0'
Es importante destacar que estamos utilizando la versión 2.1.0 de Realm, que es compatible con Kotlin 2.0. Esta compatibilidad es crucial para evitar problemas de integración en proyectos modernos.
Organizando el proyecto
Para mantener una estructura clara, es recomendable organizar nuestro código en carpetas específicas:
- Crear una carpeta
room
para todo lo relacionado con Room - Crear una carpeta
realm
para los componentes de Realm
Esta organización nos permitirá mantener una clara separación de responsabilidades y facilitará el mantenimiento del código a largo plazo.
¿Cuáles son las diferencias entre entidades de Room y objetos de Realm?
Una de las diferencias fundamentales entre Room y Realm está en cómo se definen las entidades o modelos de datos.
Creando objetos en Realm vs entidades en Room
En Room:
@Entity(tableName = "orders")
data class OrderEntity(
@PrimaryKey(autoGenerate = true)
val id: Long = 0,
val customerName: String,
val item: String,
val total: Double,
val imageUrl: String
)
En Realm:
@RealmClass
open class OrderObject : RealmObject {
@PrimaryKey
var id: String = ""
var customerName: String = ""
var item: String = ""
var total: Double = 0.0
var imageUrl: String = ""
}
Las diferencias clave son:
- Room utiliza
data class
mientras que Realm usaopen class
que extiende deRealmObject
- En Realm es obligatorio inicializar todos los atributos
- Room permite autogenerar IDs con
autoGenerate = true
, mientras que Realm no ofrece esta funcionalidad - Los objetos de Realm requieren la anotación
@RealmClass
Ejemplo de PreorderObject en Realm
@RealmClass
open class PreorderObject : RealmObject {
@PrimaryKey
var id: Long = 0
var customerName: String = ""
var item: String = ""
var isSent: Boolean = false
}
¿Cómo implementar operaciones CRUD con Realm?
Al igual que con Room, necesitamos crear clases que manejen las operaciones de base de datos, pero la sintaxis y el enfoque son diferentes.
Implementando OrderReal (equivalente a OrderDao)
class OrderReal @Inject constructor(
private val realm: Realm
) {
suspend fun insertOrders(orders: List<OrderObject>) {
realm.write {
orders.forEach { order ->
copyToRealm(order)
}
}
}
fun getOrders(): Flow<List<OrderObject>> {
return realm.query(OrderObject::class)
.find()
.asFlow()
.map { it.list }
}
suspend fun getOrder(id: String): OrderObject? {
return realm.query(OrderObject::class, "id == $0", id)
.first()
.find()
}
}
Observemos las diferencias con Room:
- En Realm usamos
write
para operaciones de escritura en lugar de anotaciones como@Insert
- Para insertar múltiples elementos, debemos iterar y usar
copyToRealm
para cada objeto - Las consultas se realizan con
query()
en lugar de métodos anotados con@Query
- Realm devuelve resultados que deben convertirse a
Flow
conasFlow()
Implementando PreorderReal
class PreorderReal @Inject constructor(
private val realm: Realm
) {
suspend fun insertPreOrder(preorderObject: PreorderObject) {
realm.write {
copyToRealm(preorderObject)
}
}
fun getPreorders(): Flow<List<PreorderObject>> {
return realm.query(PreorderObject::class)
.asFlow()
.map { it.list }
}
suspend fun deletePreorder(id: Long) {
realm.write {
query(PreorderObject::class, "id == $0", id)
.first()
.find()
?.let { delete(it) }
}
}
suspend fun updateIsSent(id: Long, isSent: Boolean) {
realm.write {
query(PreorderObject::class, "id == $0", id)
.first()
.find()
?.isSent = isSent
}
}
}
¿Cómo configurar la inyección de dependencias para Realm?
Para integrar Realm con Hilt (sistema de inyección de dependencias), necesitamos crear un módulo específico.
@Module
@InstallIn(SingletonComponent::class)
object RealmModule {
@Provides
@Singleton
fun provideRealmConfiguration(): RealmConfiguration {
return RealmConfiguration.Builder(
schema = setOf(
PreorderObject::class,
OrderObject::class
)
)
.name("realm-database.db")
.schemaVersion(1)
.build()
}
@Provides
@Singleton
fun provideRealm(configuration: RealmConfiguration): Realm {
return Realm.open(configuration)
}
}
Este módulo:
-
Proporciona una configuración de Realm que especifica:
- Las clases de esquema (nuestros objetos)
- El nombre de la base de datos
- La versión del esquema
-
Crea y proporciona una instancia de Realm utilizando la configuración anterior
La configuración es similar a la de Room, pero con la sintaxis específica de Realm.
La implementación de Realm ofrece una alternativa interesante a Room para el almacenamiento local en Android. Aunque ambas tecnologías cumplen propósitos similares, Realm se enfoca más en un modelo orientado a objetos mientras que Room está basado en SQL. Elegir entre una u otra dependerá de las necesidades específicas de tu proyecto y tu familiaridad con cada tecnología.
¿Has trabajado con Realm anteriormente? ¿Qué ventajas o desventajas has encontrado en comparación con Room? Comparte tu experiencia en los comentarios.