Menu Docs
Página inicial do Docs
/ /
Atlas Device SDKs
/ /

Managed assinaturas de sincronização - Kotlin SDK

Nesta página

  • Pré-requisitos
  • Visão geral das assinaturas
  • Assine tipos de objetos
  • Assinaturas iniciais
  • Gerencie assinaturas em seu aplicativo cliente
  • Sobre os exemplos nesta página
  • Inscrever-se para receber queries
  • Inscrever-se em uma query
  • Atualizar uma assinatura de query
  • Aguarde uma assinatura de query para sincronizar
  • Gerenciar assinaturas manualmente
  • Adicionar uma assinatura
  • Aguarde as alterações na assinatura para sincronizar
  • Estado do conjunto de assinaturas
  • Atualizar assinaturas com uma nova query
  • Remover subscrições
  • Requisitos e limitações do Flexible Sync RQL
  • Requisitos de inscrição de campos de query indexados
  • Operadores de consulta não suportados na sincronização flexível
  • Listar queries
  • Objetos incorporados ou vinculados
  • Limite de tamanho da query
  • Considerações de desempenho
  • Eficiência da API
  • Atualizações de grupo para melhorar o desempenho

usa assinaturas e permissões para determinar quais dados sincronizar com seu aplicativo. Esta página detalha como gerenciar assinaturas para Flexible Sync.

Para obter mais informações, consulte Flexible Sync na documentação do App Services.

Antes de trabalhar com assinaturas do Flexible Sync, você deve configurar seu aplicativo para usar o Realm Mobile Sync e configurar o Flexible Sync no backend.

Para fazer isso, conclua as etapas descritas no procedimento Adicionar Realm Mobile Sync ao seu aplicativo .

Ao configurar o Flexible Sync no backend, você especifica quais campos seu aplicativo cliente pode executar uma query usando assinaturas.

Cada assinatura corresponde a uma query em campos desejáveis para um tipo de objeto específico. Consulte Campos consultáveis na documentação do Atlas App Services para obter mais informações.

Para cada assinatura de query, o Realm procura dados correspondentes à query. Os dados correspondentes à assinatura, nos quais o usuário tem as permissões apropriadas, são sincronizados entre os clientes e o aplicativo de backend.

Você pode construir query com a RQL.

Importante

Flexible Sync não é compatível com todos os operadores disponíveis no RQL. Consulte LimitaçõesFlexible Sync RQL de sincronização para obter detalhes.

Os conjuntos de assinaturas são baseados no tipo de objeto. Você pode ter várias assinaturas se tiver muitos tipos de objetos do Realm. Você também pode ter várias assinaturas no mesmo tipo de objeto.

No entanto, se você utilizar objetos vinculados , objetos assimétricos ou dados geoespaciais em seu aplicativo, consulte as seguintes seções para informações adicionais:

Se seu aplicativo usar objetos vinculados, você deverá adicionar o objeto em si e seu objeto vinculado ao conjunto de assinaturas para ver o objeto vinculado real.

Quando os resultados de sua assinatura contêm um objeto com uma propriedade vinculada a um objeto não contido nos resultados, o link parece nulo. Não há como distinguir se o valor dessa propriedade é nulo ou se o objeto ao qual ela se vincula existe, mas está fora da exibição da assinatura de query..

Se o seu aplicativo usar a ingestão de dados para sincronizar unidirecionalmente objetos assimétricos, você não poderá criar assinaturas para esses objetos. Se seu aplicativo contiver objetos assimétricos e objetos não assimétricos no mesmo território, você poderá adicionar queries de assinatura do Flexible Sync para os objetos não assimétricos.

Alterado na versão 1,13,0: Dados geoespaciais suportados no Atlas Device Sync

No Kotlin SDK versão 1.13.0 e posterior, você pode criar assinaturas para query geoespaciais. Se você tentar se inscrever em uma query geoespacial com uma versão mais antiga do SDK, receberá um erro de servidor com uma gravação compensatória.

Para mais informações, consulte query de Dados Geoespaciais.

Você deve ter pelo menos uma assinatura antes de ler ou gravar no domínio.

No aplicativo cliente, você adiciona, atualiza e remove assinaturas de queries específicas nos campos consultáveis. Isso determina quais dados são sincronizados com o dispositivo cliente.

Você pode:

  • Adicione assinaturas com um nome de assinatura opcional:

    • No Kotlin SDK versão 1.10.0 e posterior, você pode usar .subscribe() para assinar um RealmQuery ou um RealmResults . Isso adiciona automaticamente a assinatura ao conjunto de assinaturas.

    • Adicione manualmente uma assinatura ao conjunto de assinatura com a API do subscriptions . Use essa API se precisar de mais controle sobre as assinaturas por motivos de otimização de desempenho ou lógica de negócios. Consulte a seção Considerações sobre desempenho para obter mais informações.

  • Reagir ao estado da assinatura

  • Atualizar assinaturas com novas queries

  • Remover assinaturas individuais ou todas as assinaturas de um tipo de objeto

Os exemplos nesta página usam um conjunto de dados para uma aplicação de lista de tarefas.

Os dois Tipo de objeto de Realm são Team e Task:

class Task : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId()
var taskName: String = ""
var assignee: String? = null
var completed: Boolean = false
var progressMinutes: Int = 0
var dueDate: RealmInstant? = null
}
class Team : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId()
var teamName: String = ""
var tasks: RealmList<Task>? = realmListOf()
var members: RealmList<String> = realmListOf()
}

Os exemplos nesta página também assumem que você tem um usuário autorizado e uma Flexible Sync SyncConfiguration():

// Login with authorized user and define a Flexible Sync SyncConfiguration
val app = App.create(YOUR_APP_ID)
val user = app.login(credentials)
val flexSyncConfig = SyncConfiguration.Builder(user, setOf(Task::class, Team::class))
.initialSubscriptions {
// Define the initial subscription set for the realm ...
}
.build()
// Open the synced realm and manage subscriptions
val realm = Realm.open(flexSyncConfig)
Log.v("Successfully opened realm: ${realm.configuration}")

Novidade na versão 1.10.0.

Para simplificar o gerenciamento de assinatura , Realm Kotlin SDK versão 1.10.0 adiciona um arquivo .subscribe() experimental API para assinar um conjunto RealmQuery ou RealmResults . Essa API abstrai os detalhes de adicionar e remover assinaturas manualmente por meio de conjuntos de assinatura .

Você pode:

  • Assinar automaticamente uma query com um nome opcional

  • Atualizar uma assinatura nomeada com uma nova query

Se precisar de mais controle sobre as assinaturas por motivos de otimização de desempenho ou lógica de negócios, você poderá gerenciar manualmente o conjunto de assinaturas usando a API subscriptions . Consulte a seção Considerações sobre desempenho para obter mais informações.

Você pode .subscribe() a uma query para criar uma assinatura para objetos correspondentes a uma query específica:

// Subscribe to a specific query
val realmResults = realm.query<Task>("progressMinutes >= $0", 60)
.subscribe()
// Subscribe to all objects of a specific type
val realmQuery = realm.query<Team>()
realmQuery.subscribe()

Isso cria uma assinatura sem nome e a adiciona ao MutableSubscriptionSet, em vez de exigir que você adicione manualmente a assinatura ao conjunto de assinatura .

Se seu aplicativo funcionar com várias assinaturas ou se você quiser atualizar uma assinatura, talvez queira adicionar um nome ao assinar uma query. Posteriormente, você poderá usar esse nome para atualizar a query da assinatura ou remover a query por nome.

Para adicionar um nome à assinatura, passe uma string ao chamar .subscribe() :

// Add a subscription named "team_developer_education"
val results = realm.query<Team>("teamName == $0", "Developer Education")
.subscribe("team_developer_education")

Você pode atualizar uma assinatura de query nomeada com uma nova query definindo updateExisting como true:

// Create a subscription named "bob_smith_teams"
val results = realm.query<Team>("$0 IN members", "Bob Smith")
.subscribe("bob_smith_teams")
// Add another subscription with the same name with `updateExisting` set to true
// to replace the existing subscription
val updateResults =
realm.query<Team>("$0 IN members AND teamName == $1", "Bob Smith", "QA")
.subscribe("bob_smith_teams", updateExisting = true)

Isso atualiza a assinatura automaticamente, em vez de exigir que você atualize manualmente a assinatura no conjunto de assinatura .

Quando você assina o conjunto de resultados de uma query, esse conjunto não contém objetos até que seja sincronizado. Se o seu aplicativo criar objetos, talvez você não precise baixar os dados sincronizados antes de o usuário trabalhar com ele. No entanto, se seu aplicativo exigir dados do servidor antes que o usuário possa trabalhar com ele, você pode especificar que o aplicativo deve aguardar a sincronização dos dados. Isso bloqueia a execução do aplicativo até que os dados sejam sincronizados com o servidor.

val results = realm.query<Team>("$0 IN members", "Bob Smith")
.subscribe("bob_smith_teams", updateExisting = false, WaitForSync.ALWAYS)
// After waiting for sync, the results set contains all the objects
// that match the query - in our case, 1
println("The number of teams that have Bob Smith as a member is ${results.size}")

Esta opção utiliza o enumeração WaitForSync , cujos valores são:

  • FIRST_TIME: (padrão) Espere para baixar objetos correspondentes quando seu aplicativo cria inicialmente a assinatura. Caso contrário, volte sem aguardar novos downloads. O aplicativo deve ter uma conexão com a internet para baixar os dados quando você adiciona inicialmente a assinatura. Opcionalmente, você pode especificar um valor timeout .

  • ALWAYS: Aguarde o download dos objetos correspondentes toda vez que o método .subscribe() for chamado. O aplicativo deve ter uma conexão de internet para baixar os dados. Opcionalmente, você pode especificar um valor timeout .

  • NEVER: Nunca espere para baixar objetos correspondentes. O aplicativo precisa de uma conexão com a Internet para que o usuário se autentique na primeira vez que o aplicativo for iniciado, mas pode ser aberto offline nas execuções subsequentes usando credenciais em cache.

Na aplicação cliente, use a API do subscriptions para managed manualmente um conjunto de assinaturas. Com esta API, você pode adicionar, atualizar ou remover query específicas em campo consultáveis. Essas queries determinam quais dados são sincronizados com o dispositivo cliente.

No Kotlin SDK versão 1.10.0 e posterior, você pode adicionar assinaturas automaticamente com o arquivo .subscribe() API. Essa API adiciona assinaturas a um MutableSubscriptionSet diretamente de um RealmQuery ou RealmResults.

Você pode adicionar uma assinatura sem nome ou uma assinatura nomeada.

Dica

Especificar um nome de assinatura

Sempre especifique um nome de assinatura se seu aplicativo usar várias assinaturas. Isso torna mais fácil procurar, atualizar e excluir suas assinaturas em outro lugar do seu aplicativo.

Para criar manualmente uma assinatura, adicione a assinatura em um bloco de atualização de assinaturas. Você anexa cada nova assinatura às assinaturas do Realm do cliente.

realm.subscriptions.update {
add(
realm.query<Task>("progressMinutes >= $0",60)
)
}

Você também pode especificar um nome de assinatura ao criar a assinatura:

// Add a subscription named "team_dev_ed"
realm.subscriptions.update { realm ->
add(
realm.query<Team>("teamName == $0", "Developer Education"),
name = "team_dev_ed"
)
}

Importante

Links de objetos

Você deve adicionar um objeto e seu objeto vinculado ao conjunto de assinaturas para ver um objeto vinculado.

Se os resultados de sua assinatura contiverem um objeto com uma propriedade vinculada a um objeto não contido nos resultados, o link parecerá nulo. Não há como distinguir se o valor dessa propriedade é nulo ou se o objeto ao qual ela se vincula existe, mas não está disponível para o cliente devido à falta de assinaturas.

Você deve ter pelo menos uma assinatura antes de ler ou escrever no Realm. Você pode inicializar um Realm com uma assinatura inicial definida ao abri-lo com o SyncConfiguration(). Consulte Abrir um Realm Sincronizado para obter mais informações.

Passe o parâmetro initialSubscriptions com as query de assinatura que você deseja utilizar para embalar o Realm:

// Bootstrap the realm with an initial query to subscribe to
val flexSyncConfig =
SyncConfiguration.Builder(user, setOf(Team::class, Task::class))
.initialSubscriptions { realm ->
add(
realm.query<Team>("$0 IN members", "Bob Smith"),
"bob_smith_teams"
)
}
.build()

Se o seu aplicativo precisar executar novamente essa assinatura inicial toda vez que for iniciado, você poderá passar um parâmetro adicional: rerunOnOpen. Este é um booleano que indica se a assinatura inicial deve ser executada novamente toda vez que o aplicativo iniciar. Talvez você precise fazer isso para executar novamente intervalos de tempo dinâmicos ou outras query que exijam um novo cálculo de variáveis estáticas para a assinatura.

Neste exemplo, queremos apenas tarefas incompletas. Com rerunOnOpen definido como true, a query recalcula dinamicamente os objetos relevantes a serem sincronizados com base nos resultados desejados da query toda vez que o aplicativo é iniciado:

// `rerunOnOpen` lets the app recalculate this query every time the app opens
val rerunOnOpenConfig =
SyncConfiguration.Builder(user, setOf(Team::class, Task::class))
.initialSubscriptions(rerunOnOpen = true) { realm ->
add(
realm.query<Team>("completed == $0", false)
)
}
.build()

Escrever uma atualização para o conjunto de assinaturas localmente é apenas um componente da alteração de uma assinatura. Após a alteração da assinatura local, o cliente sincroniza com o servidor para resolver quaisquer atualizações nos dados devido à alteração da assinatura. Isso pode média adicionar ou remover dados do Realm sincronizado.

Use o método SyncConfiguration.waitForInitialRemoteData() método construtor para forçar seu aplicação a bloquear até que os dados de assinatura do cliente sejam sincronizados com o backend antes de abrir o Realm:

// Update the list of subscriptions
realm.subscriptions.update {
add(
realm.query<Team>("$0 IN members", "Jane Doe"),
"jane_doe_teams"
)
}
// Wait for subscription to fully synchronize changes
realm.subscriptions.waitForSynchronization(Duration.parse("10s"))

Você também pode usar SubscriptionSet.waitForSynchronization() para atrasar a execução até que a sincronização da assinatura seja concluída após instanciar uma conexão de sincronização.

Use a propriedade SubscriptionSet.state para ler o estado atual do conjunto de assinaturas.

SUPERCEDED (sic -- observe a ortografia alternativa) é um SubscriptionSetState que pode ocorrer quando outro thread escreve uma assinatura em uma instância diferente do conjunto de assinaturas. Se o estado se tornar SUPERCEDED, você deverá obter uma nova instância do conjunto de assinaturas antes de poder gravar nele.

Observação

Estado da assinatura "Concluído"

O estado do conjunto de assinaturas "complete" não significa que a sincronização "está concluída" ou "todos os documentos foram sincronizados". "Completo" significa que as duas coisas a seguir aconteceram:

  • A assinatura se tornou o conjunto de assinaturas ativo que está sendo atualmente sincronizado com o servidor.

  • Os documentos que correspondiam à assinatura no momento em que a assinatura foi enviada ao servidor agora estão no dispositivo local. Observe que isso não inclui necessariamente todos os documentos que atualmente correspondem à assinatura.

O SDK do Realm não fornece uma maneira de verificar se todos os documentos que correspondem a uma assinatura foram sincronizados com o dispositivo.

Você pode atualizar assinaturas usando SubscriptionSet.update().

Neste exemplo, usamos MutableSubscriptionSet.add(). para atualizar a query da assinatura denominada "bob_smith_teams". Você deve definir o parâmetro updateExisting como true para atualizar uma assinatura com add():

// Create a subscription named "bob_smith_teams"
realm.subscriptions.update {
add(
realm.query<Team>("$0 IN members", "Bob Smith"),
"bob_smith_teams"
)
}
// Set `updateExisting` to true to replace the existing
// "bob_smith_teams" subscription
realm.subscriptions.update {
add(
realm.query<Team>("$0 IN members AND $1 IN members", "Bob Smith", "Jane Doe"),
"bob_smith_teams", updateExisting = true
)
}

Você não pode atualizar assinaturas criadas sem um nome. No entanto, você pode procurar assinaturas não nomeadas por query, removê-las do conjunto de assinaturas e adicionar uma nova assinatura com uma query atualizada:

// Search for the subscription by query
val subscription =
realm.subscriptions.findByQuery(
realm.query<Team>("teamName == $0", "Developer Education")
)
// Remove the returned subscription and add the updated query
if (subscription != null) {
realm.subscriptions.update {
remove(subscription)
add(
realm.query<Team>("teamName == $0", "DevEd"),
"team_developer_education"
)
}
}

Para remover assinaturas, você pode:

  • Remover uma query de assinatura única

  • Remover todas as assinaturas de um tipo de objeto específico

  • Remover todas as assinaturas

  • Remover todas as assinaturas sem nome

Quando você remove uma query de assinatura, o Realm remove assíncronamente os dados sincronizados que corresponderam à query do dispositivo cliente.

Você pode remover uma query de assinatura específica usando MutableSubscriptionSet.remove(). Você pode procurar a assinatura por nome e, em seguida, passar a assinatura retornada para remove() ou passar o nome da assinatura diretamente para remove():

realm.subscriptions.update {
add(
realm.query<Team>("$0 IN members", "Bob Smith"),
"bob_smith_teams"
)
}
// Wait for synchronization to complete before updating subscriptions
realm.subscriptions.waitForSynchronization(Duration.parse("10s"))
// Remove subscription by name
realm.subscriptions.update {
remove("bob_smith_teams")
}

Se você quiser remover todas as assinaturas de um tipo de objeto específico, passe uma classe para o MutableSubscriptionSet.removeAll(). método:

realm.subscriptions.update {
add(
realm.query<Team>("$0 IN members", "Bob Smith"),
"bob_smith_teams")
}
// Wait for synchronization to complete before updating subscriptions
realm.subscriptions.waitForSynchronization(Duration.parse("10s"))
// Remove all subscriptions to type Team
realm.subscriptions.update {
removeAll(Team::class)
}

Para remover todas as assinatura do conjunto de assinaturas, use MutableSubscriptionSet.removeAll(). sem argumentos:

Aviso

Se você remover todas as assinaturas e não adicionar uma nova, receberá um erro. Um domínio aberto com uma configuração de Flexible Sync precisa de pelo menos uma assinatura para sincronizar com o servidor.

// Remove all subscriptions
realm.subscriptions.update {
removeAll()
}

Novidade na versão 1.10.0.

Você pode querer remover assinaturas não nomeadas que são transitórias ou geradas dinamicamente, mas deixar assinaturas nomeadas em vigor.

Você pode remover todas as assinaturas não nomeadas (anônimas) do conjunto de assinaturas configurando anonymousOnly para true quando você chamar o método removeAll :

// Remove all unnamed (anonymous) subscriptions
realm.subscriptions.update {
removeAll(anonymousOnly = true)
}

Adicionar um campo de query indexado à sua aplicação pode melhorar o desempenho de queries simples em dados fortemente particionados. Por exemplo, uma aplicação onde as queries mapeiam fortemente os dados para um dispositivo, armazém ou usuário, como user_id == $0, “641374b03725038381d2e1fb”, é uma boa candidata para um campo de query indexado. No entanto, um campo de query indexado tem requisitos específicos para uso em uma inscrição de query:

  • O campo de query indexado deve ser usado em todas as inscrições de query. Não pode estar faltando na query.

  • O campo de query indexado deve usar uma comparação == ou IN com uma constante pelo menos uma vez na query de inscrição. Por exemplo, user_id == $0, "641374b03725038381d2e1fb" ou store_id IN $0, {1,2,3}.

Opcionalmente, você pode incluir uma comparação AND, desde que o campo consultável indexado seja comparado diretamente com uma constante usando == ou IN pelo menos uma vez. Por exemplo, store_id IN {1,2,3} AND region=="Northeast" ou store_id == 1 AND (active_promotions < 5 OR num_employees < 10).

As consultas inválidas do Flexible Sync em um campo indexado que pode ser consultado incluem consultas em que:

  • O campo de consulta indexado não utiliza AND com o resto da consulta. Por exemplo store_id IN {1,2,3} OR region=="Northeast" é inválido porque usa OR em vez de AND. Da mesma forma, store_id == 1 AND active_promotions < 5 OR num_employees < 10 é inválido porque o AND só se aplica ao termo ao lado, não à consulta inteira.

  • O campo de consulta indexado não é utilizado em um operador de igualdade. Por exemplo store_id > 2 AND region=="Northeast" é inválido porque utiliza apenas o operador > com o campo de consulta indexado e não tem uma comparação de igualdade.

  • A query está totalmente ausente do campo de query indexado. Por exemplo, region=="Northeast ou truepredicate são inválidos porque não contêm o campo de query indexado.

A Flexible Sync tem algumas limitações ao usar operadores RQL. Quando você escreve a assinatura de consulta que determina quais dados sincronizar, o servidor não oferece suporte a esses operadores de consulta. No entanto, você ainda pode usar toda a gama de recursos de RQL para consultar o conjunto de dados sincronizado no aplicativo cliente.

Tipo de operador
Operadores não suportados

Operadores agregados

@avg, @count, @max, @min, @sum

Sufixos de query

DISTINCT, SORT , LIMIT

Queries que não diferenciam maiúsculas de minúsculas ([c]) não podem usar índices de forma eficaz. Sendo assim, queries que não diferenciam maiúsculas de minúsculas não são recomendadas, pois podem causar problemas de desempenho.

A sincronização flexível suporta apenas @count para campos de array.

A sincronização flexível oferece suporte às listas de query usando o operador IN .

Você pode consultar uma lista de constantes para ver se ela contém o valor de um campo de consulta:

// Query a constant list for a queryable field value
"priority IN { 1, 2, 3 }"

Se um campo de query tiver um valor de array, você poderá consultar para ver se ele contém um valor constante:

// Query an array-valued queryable field for a constant value
"'comedy' IN genres"

Aviso

Não é possível comparar duas listas entre si em uma consulta de sincronização flexível. Observe que esta é uma sintaxe válida do Realm Query Language fora das consultas do Flexible Sync.

// Invalid Flexible Sync query. Do not do this!
"{'comedy', 'horror', 'suspense'} IN genres"
// Another invalid Flexible Sync query. Do not do this!
"ANY {'comedy', 'horror', 'suspense'} != ANY genres"

A Flexible Sync não oferece suporte à consulta de propriedades em objetos ou links embarcados. Por exemplo, obj1.field == "foo".

O limite de tamanho para qualquer assinatura de query em seu conjunto de assinatura é de 256 kB. Exceder esse limite resulta em um erro de LimitsExceeded.

O gerenciamento de várias assinaturas com a API .subscribe() descrita na seção Assinar queries é menos eficiente do que executar atualizações em lote quando você gerencia assinaturas manualmente por meio da API do conjunto de assinaturas. Para obter melhor desempenho ao fazer várias alterações na assinatura, use a API subscriptions.update descrita na seção Gerenciar assinaturas manualmente .

Cada transação de escrita para um conjunto de assinaturas tem um custo de desempenho. Se você precisar fazer várias atualizações em um objeto do Realm durante uma sessão, considere manter objetos editados na memória até que todas as alterações sejam concluídas. Isso melhora o desempenho da sincronização, gravando apenas o objeto completo e atualizado em seu domínio, em vez de cada alteração.

Voltar

Configurar e abrir um domínio sincronizado