Esta página contiene instrucciones para integrar rápidamente Realm en una aplicación de Android de ejemplo que utiliza Datos en vivoEsta aplicación de ejemplo permite a un usuario incrementar un contador usando un botón.
Requisitos previos
Esta guía de inicio rápido utiliza Sync para sincronizar los cambios de datos entre clientes. Antes de comenzar, asegúrese de tener:
Nota
Uso de LiveData sin sincronización
Para usar esta guía de inicio rápido sin sincronización, deshabilite las funciones de sincronización en el SDK. Puede hacerlo eliminando las siguientes líneas del archivo build.gradle de la aplicación:
realm { syncEnabled = true }
Después de eliminar las líneas, vuelva a sincronizar la configuración de Gradle para volver a cargar el SDK de Java en modo sin conexión. Elimine las líneas relacionadas con la importación y el uso de la configuración de sincronización, el inicio de sesión de usuario y los valores de partición de CounterModel archivo para utilizar el SDK de Java sin sincronización.
Clonar el repositorio de inicio rápido de LiveData
Para comenzar, copie el repositorio de ejemplo en su entorno local.
Ya hemos creado una aplicación para Android con la mayor parte del código necesario. Puedes clonar el repositorio de la aplicación cliente directamente desde GitHub:
git clone https://github.com/mongodb-university/realm-android-livedata.git
El repositorio contiene dos ramas: final y start. La rama final es una versión terminada de la aplicación como debe verse después de que completes este tutorial. Para seguir este tutorial, por favor revisa la rama start:
git checkout start
Dependencias de importación
Ahora que has clonado el repositorio, necesitas agregar las dependencias necesarias para ejecutar el SDK de Java y Android LiveData. Comienza agregando la dependencia del SDK de Java al bloque buildscript.dependencies del archivo build.gradle de tu proyecto:
buildscript { ext.kotlin_version = "1.4.10" repositories { google() jcenter() } dependencies { classpath "com.android.tools.build:gradle:4.0.2" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "io.realm:realm-gradle-plugin:10.2.0" } }
También tendrás que agregar la dependencia Android LiveData al bloque dependencies de tu archivo de nivel de aplicación build.gradle:
dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
A continuación, habilite la sincronización en el SDK creando el siguiente bloque de nivel superior en el archivo de nivel de aplicación build.gradle:
realm { syncEnabled = true }
Luego, habilite DataBinding creando el siguiente bloque en el bloque android de su archivo de nivel de aplicación build.gradle:
android { compileSdkVersion 30 buildToolsVersion "30.0.2" defaultConfig { applicationId "com.mongodb.realm.livedataquickstart" minSdkVersion 16 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildFeatures { dataBinding true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } }
Por último, haga clic en el botón "Sincronizar" o seleccione Build > Rebuild Project en el menú de la aplicación para reconfigurar su configuración de Gradle con estos cambios y obtener las dependencias.
Objeto LiveRealm
Con todas las dependencias en su lugar, es hora de crear una interfaz compatible con LiveData para nuestros objetos Realm. Para hacerlo, deberemos gestionar algunos eventos:
El método
onActive()permite que un observador se suscriba a los cambios en el objeto Realm subyacente agregando un detector de cambios.override fun onActive() { super.onActive() val obj = value if (obj != null && RealmObject.isValid(obj)) { RealmObject.addChangeListener(obj, listener) } } El método
onInactive()permite que un observador cancele la suscripción a los cambios en el objeto Realm subyacente eliminando el detector de cambios.override fun onInactive() { super.onInactive() val obj = value if (obj != null && RealmObject.isValid(obj)) { RealmObject.removeChangeListener(obj, listener) } } Cuando se produce un cambio, el miembro
listenerutiliza el métodosetValue()de la clase padreLiveDatapara pasar el valor del objeto Realm a la UI a menos que el objeto se haya eliminado, en cuyo caso el detector de cambios pasa un valor denullen lugar de pasar una referencia a un objeto eliminado no válido.private val listener = RealmObjectChangeListener<T> { obj, objectChangeSet -> if (!objectChangeSet!!.isDeleted) { setValue(obj) } else { // Because invalidated objects are unsafe to set in LiveData, pass null instead. setValue(null) } }
Tip
Uso de LiveData con RealmResults
Este ejemplo solo usa LiveData para mostrar RealmObjects en la interfaz de usuario. Para ver un ejemplo de implementación que RealmResults muestra, consulte LiveRealmResults.
Creación de instancias de LiveData en ViewModel
Esta aplicación almacena toda su lógica y datos principales en un ViewModel llamado CounterModel. Al ejecutarse, crea una instancia de CounterModel que se utiliza hasta que se cierra. Esta instancia contiene los LiveData que se muestran en la interfaz de usuario de la aplicación. Para crear una instancia de LiveData, necesitamos acceder a un objeto Counter almacenado en un dominio y pasarlo al constructor LiveRealmObject. Para ello:
Conéctese a su aplicación con su ID de aplicación.
Autenticar un usuario.
Conéctese a un reino específico mediante Sincronización.
Consulta el reino en busca de un
Counter, insertando un nuevoCountersi aún no se ha creado uno en este reino.Cree una instancia de
LiveRealmObjectutilizando la instanciaCountery almacénela en el miembrocounterdeCounterModel.
El siguiente fragmento de código implementa este comportamiento:
init { val appID = "YOUR APP ID HERE" // TODO: replace this with your App ID // 1. connect to the MongoDB Realm app backend val app = App( AppConfiguration.Builder(appID) .build() ) // 2. authenticate a user app.loginAsync(Credentials.anonymous()) { if(it.isSuccess) { Log.v("QUICKSTART", "Successfully logged in anonymously.") // 3. connect to a realm with Realm Sync val user: User? = app.currentUser() val partitionValue = "example partition" val config = SyncConfiguration.Builder(user!!, partitionValue) // because this application only reads/writes small amounts of data, it's OK to read/write from the UI thread .allowWritesOnUiThread(true) .allowQueriesOnUiThread(true) .build() // open the realm realm = Realm.getInstance(config) // 4. Query the realm for a Counter, creating a new Counter if one doesn't already exist // access all counters stored in this realm val counterQuery = realm!!.where<Counter>() val counters = counterQuery.findAll() // if we haven't created the one counter for this app before (as on first launch), create it now if (counters.size == 0) { realm?.executeTransaction { transactionRealm -> val counter = Counter() transactionRealm.insert(counter) } } // 5. Instantiate a LiveRealmObject using the Counter and store it in a member variable // the counters query is life, so we can just grab the 0th index to get a guaranteed counter this._counter.postValue(counters[0]!!) } else { Log.e("QUICKSTART", "Failed to log in anonymously. Error: ${it.error.message}") } } }
Importante
No lea ni escriba en el hilo de UI
Las lecturas y escrituras en la base de datos son computacionalmente costosas, por lo que el SDK las deshabilita por defecto en el hilo de la interfaz de usuario. Para simplificar, este ejemplo habilita las lecturas y escrituras en el hilo de la interfaz de usuario con los métodos de configuración allowWritesOnUiThread() y allowQueriesOnUiThread(). En aplicaciones de producción, casi siempre se recomienda aplazar las lecturas y escrituras a un hilo en segundo plano mediante métodos asíncronos.
Conectando el ViewModel a la UI
Para mostrar los datos almacenados en en la CounterModel interfaz de usuario de la aplicación, necesitamos acceder CounterModel al singleton mediante el método viewModels() cuando la aplicación CounterFragment crea. Una vez instanciado el modelo, podemos usar la biblioteca de enlace de datos de Android para mostrar los datos del modelo en los elementos de la interfaz de usuario.
Para acceder al singleton CounterModel cuando la aplicación crea CounterFragment, coloque el siguiente código en el método onCreateView() de CounterFragment:
val model: CounterModel by viewModels()
A continuación, configure los hooks de Data Binding en la UI para el fragmento del contador:
<?xml version="1.0" encoding="utf-8"?> <layout> <data> <variable name="counterModel" type="com.mongodb.realm.livedataquickstart.model.CounterModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".CounterFragment"> <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{counterModel.counter.value.get().toString()}" android:textSize="58pt" app:layout_constraintBottom_toTopOf="@id/button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/add" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/textview" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
Por último, conecte el modelo al enlace para que la interfaz de usuario pueda mostrar el contador e iterarlo al presionar el botón con el siguiente código en el método onCreateView() de CounterFragment:
val binding = CounterFragmentBinding.inflate(inflater, container, false).apply { lifecycleOwner = viewLifecycleOwner counterModel = model } binding.root.button.setOnClickListener { Log.v("QUICKSTART", "Clicked increment button. Current value: ${model.counter.value?.value?.get()}") model.incrementCounter() } return binding.root
Ejecutar la aplicación
Ahora debería poder ejecutar la aplicación de ejemplo. Verá una interfaz similar a esta:

Al hacer clic en el botón "AÑADIR", el valor de tu contador se incrementará en uno. Con Sync, puedes consultar los registros de tu aplicación para ver eventos de incremento individuales. Android LiveData tiene en cuenta el ciclo de vida, por lo que girar la pantalla o liberar el estado de la aplicación borrando la RAM del dispositivo no debería afectar su estado, que debería reanudarse sin problemas y volver a suscribirse automáticamente a los eventos al reanudarse, utilizando el estado almacenado en el singleton del modelo y la instancia encapsulada de LiveData.
Resumen
Utilice las clases
LiveRealmObjectyLiveRealmResultscomo plantilla para encapsular datos de Realm en vivo en Android LiveData.Utilice un ViewModel para separar los datos subyacentes de los elementos de la interfaz de usuario que muestran esos datos.
DataBinding le permite declarar relaciones entre los datos del modelo y los elementos de la interfaz de usuario sin establecer valores explícitamente en una actividad o fragmento.
Comentarios
¿Te resultó útil esta guía de inicio rápido? ¡Comparte tu opinión con nosotros a través del formulario de comentarios a la derecha de la página!