Esta página contém instruções para integrar rapidamente o Realm a um exemplo de aplicação Android que usa LiveData. Este aplicação de exemplo permite que um usuário incremente um contador usando um botão.
Pré-requisitos
Este guia de início rápido usa o Sync para sincronizar alterações de dados entre clientes. Antes de começar, verifique se tem:
Observação
Usando LiveData sem Sincronizar
Para usar esse início rápido sem o Sync, desative os recursos de sincronização no SDK. Você pode fazer isso removendo as seguintes linhas do arquivo build.gradle
no nível do aplicativo:
realm { syncEnabled = true }
Depois de remover as linhas, sincronize novamente a configuração do Gradle para recarregar o Java SDK em um estado somente offline. Remova as linhas relacionadas à importação e ao uso da Configuração de sincronização, do login do usuário e do valor da partição do arquivo CounterModel
para usar o Java SDK sem sincronização.
Clonar o repositório de início rápido do LiveData
Para começar, copie o repositório de exemplo em seu ambiente local.
Já reunimos um aplicativo Android que tem a maior parte do código de que você precisa. Você pode clonar o repositório de aplicação do cliente diretamente do Github:
git clone https://github.com/mongodb-university/realm-android-livedata.git
O repositório contém duas ramificações: final
e start
. A ramificação final
é uma versão finalizada do aplicativo, pois ela deve procurar depois que você concluir este tutorial. Para aprender este tutorial, confira a ramificação start
:
git checkout start
Importar dependências
Agora que você clonou o repositório, precisa adicionar as dependências necessárias para executar o Java SDK e o Android LiveData. Comece adicionando a dependência do Java SDK ao bloco buildscript.dependencies
do seu arquivo build.gradle
no nível do projeto:
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" } }
Você também terá que adicionar a dependência Android LiveData ao bloco dependencies
do seu arquivo build.gradle
de nível de aplicativo:
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' }
Em seguida, habilite a Sincronização no SDK criando o seguinte bloco de nível superior no arquivo build.gradle
do nível do aplicativo:
realm { syncEnabled = true }
Em seguida, habilite o DataBinding criando o seguinte bloco no bloco android
do seu arquivo de nível de aplicativo 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 fim, clique no botão "Sincronizar" ou selecione Build > Rebuild Project no menu do aplicativo para reconfigurar a configuração do Gradle com essas alterações e obter as dependências.
LiveRealmObject
Com todas as dependências em vigor, é hora de criar uma interface compatível com LiveData para nossos Objeto de Realm. Para fazer isso, teremos que lidar com alguns eventos:
O método
onActive()
permite que um observador assine alterações no objeto Realm subjacente adicionando um ouvinte de alterações.override fun onActive() { super.onActive() val obj = value if (obj != null && RealmObject.isValid(obj)) { RealmObject.addChangeListener(obj, listener) } } O método
onInactive()
permite que um observador cancele a assinatura de alterações no Objeto de Realm subjacente removendo o ouvinte de alterações.override fun onInactive() { super.onInactive() val obj = value if (obj != null && RealmObject.isValid(obj)) { RealmObject.removeChangeListener(obj, listener) } } Quando ocorre uma alteração, o
listener
membro usa osetValue()
método daLiveData
classe pai para passar o valor do objeto Realm para a UI, a menos que o objeto tenha sido excluído, caso em que o ouvinte de alterações passa um valor de emnull
vez de passar uma referência para um objeto inválido e excluído.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) } }
Dica
Uso de LiveData com RealmResults
Este exemplo utiliza somente LiveData para exibir RealmObjects
na interface do usuário. Para uma implementação de amostra RealmResults
exibindo, consulte LiveRealmResults.
Instanciando LiveData no ViewModel
Este aplicativo armazena toda a sua lógica e dados principais dentro de um ViewModel chamado CounterModel
. Quando o aplicativo é executado, ele cria uma instância do CounterModel
que é utilizada até o aplicativo ser fechado. Essa instância contém o LiveData exibido na interface do usuário do aplicativo. Para criar uma instância do LiveData, precisamos acessar um objeto Counter
armazenado em um domínio e passá-lo para o construtor LiveRealmObject
. Para fazer isso:
Conecte-se ao seu aplicativo com seu ID do aplicativo.
Autenticar um usuário.
Conecte-se a um Realm específico usando a sincronização.
query o Realm em busca de um
Counter
, inserindo um novoCounter
se um ainda não tiver sido criado nesse Realm.Instancie um
LiveRealmObject
utilizando a instância doCounter
e armazene-o no membrocounter
deCounterModel
.
O seguinte trecho de código implementa esse comportamento:
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
Não leia ou escreva na thread da interface do usuário
As leituras e gravações de reconhecimento de data center são computacionalmente caras, portanto, o SDK desativa as leituras e gravações por padrão no thread da UI. Para simplificar, este exemplo permite leituras e gravações de thread da UI com os métodos do construtor de configuração allowWritesOnUiThread()
e allowQueriesOnUiThread()
. Em aplicativos de produção, você deve quase sempre adiar leituras e gravações para um thread em segundo plano usando métodos assíncronos.
Conectando o ViewModel à UI
Para exibir os dados armazenados no na CounterModel
interface CounterModel
do usuário do aplicação , precisaremos acessar o singleton do utilizando o método viewModels() quando o aplicação criar CounterFragment
o. Depois de instanciar o modelo, podemos usar a biblioteca Android Data Binding para exibir os dados do modelo em elementos da UI.
Para acessar o singleton CounterModel
quando o aplicativo cria CounterFragment
, coloque o seguinte código no método onCreateView()
de CounterFragment
:
val model: CounterModel by viewModels()
Em seguida, configure os ganchos de vinculação de dados na interface do usuário para o fragmento do 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 fim, conecte o modelo à associação para que a UI possa exibir o contador e iterar o contador ao pressionar o botão com o seguinte código no 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
Executar o aplicativo
Agora você deve ser capaz de executar o aplicativo de amostra. Você deve ver uma interface parecida com esta:

Clicar no botão "ADD" deve adicionar um ao valor do seu contador. Com a sincronização, você pode ver seus registros de aplicações para ver eventos de incremento individuais. O Android LiveData reconhece o ciclo de vida, portanto, girar a tela ou liberar o estado do aplicativo limpando a RAM do dispositivo não deve afetar o estado do aplicativo, que deve ser retomado sem problemas e assinado novamente automaticamente os eventos na retomada usando o estado armazenado no modelo único e a instância LiveData encapsulada.
Resumo
Use as classes
LiveRealmObject
eLiveRealmResults
como modelo para encapsular dados ativos do Realm no Android LiveData.Use um ViewModel para separar os dados subjacentes dos elementos da interface do usuário que exibem esses dados.
O DataBinding permite que você declare relacionamentos entre os dados do modelo e os elementos da interface do usuário sem definir explicitamente os valores em uma atividade ou fragmento.
Feedback
Você encontrou este guia de início rápido útil? Informe-nos com o formulário de feedback no lado direito da página!