Segmentação - SDK Java
Nesta página
Para tornar seus aplicativos Android rápidos e responsivos, você deve equilibrar o tempo de computação necessário para organizar os visuais e lidar com interações do usuário com o tempo necessário para processar seus dados e executar sua lógica de negócios. Tipicamente, desenvolvedores de aplicativos distribuem esse trabalho em vários threads: o principal ou thread de UI para todo o trabalho relacionado à interface do usuário, e um ou mais threads de background para calcular volumes de trabalho mais pesados antes de enviá-los ao thread de UI para apresentação. Ao transferir trabalhos pesados para threads de background, o thread de UI pode permanecer altamente responsivo, independentemente do tamanho do volume de trabalho.
Três regras a ter em conta
O Realm habilita a programação simples e segura de várias threads seguindo estas três regras:
- Evite escritas na thread da UI se escrever em uma thread em background:
- Você pode escrever em um Realm de qualquer thread, mas só pode haver um escritor por vez. Consequentemente, transações de escrita bloqueiam umas às outras. Uma escrita na thread da UI pode fazer com que seu aplicativo pareça não responsivo enquanto espera que uma escrita em uma thread de segundo plano seja concluída. Se você estiver usando Sync, evite escrever no thread da interface do usuário enquanto o Sync escreve em um thread de background.
- Não passe objetos ativos, coleções ou realms para outras threads:
- Objetos ativos, collections e instâncias de Realm são confinados à thread: ou seja, são válidos somente na thread em que foram criados. De forma prática, isso significa que não é possível passar instâncias ativas para outras threads. No entanto, o Realm oferece vários mecanismos para compartilhar objetos entre threads.
- Não trave a leitura:
- A arquitetura de controle de concorrência multiversão (MVCC) da Realm elimina a necessidade de bloqueio para operações de leitura. Os valores que você lê nunca serão corrompidos ou em um estado parcialmente modificado. Você pode ler livremente a partir de domínios em qualquer thread sem a necessidade de bloqueios ou mutexes. O bloqueio desnecessário seria um gargalo de desempenho, pois cada thread poderia precisar esperar sua vez antes de ler.
Comunicação entre threads
Objeto ativos, collection e realms são confinados a threads. Se você precisar trabalhar com os mesmos dados em vários threads, deverá abrir o mesmo realm em vários threads como instâncias de realm separadas. O Java SDK unifica conexões subjacentes entre threads sempre que possível para tornar esse padrão mais eficiente.
Quando há necessidade de comunicação entre threads, você tem várias opções, dependendo do seu caso de uso:
Para modificar os dados em dois threads, consulte o objeto em ambos os threads usando uma chave primária.
Para enviar uma visualização rápida e somente leitura de um objeto para outros threads, congele o objeto.
Para manter e compartilhar muitas visualizações somente para leitura do objeto em sua aplicação, copie o objeto de realm.
Para reagir às alterações feitas em qualquer tópico, use as notificações.
Para ver as alterações de outras threads no realm na thread atual, atualize sua instância de realm (as threads de loop de eventos são atualizadas automaticamente).
Intenções
GERENCIADO RealmObject
As instâncias não são seguras para thread ou Parcelable
, portanto, você não pode passá-las entre atividades ou threads por meio de um Intent
. Em vez disso, você pode passar um ObjectId, como uma chave primária, no pacote Intent
extras e, em seguida, abrir uma nova instância de realm no thread separado para fazer query desse identificador. Alternativamente, você pode congelar objetos de Realm.
Dica
Veja também:
Você pode encontrar exemplos de trabalho em Passar objetos parte do Exemplo de threading do Java SDK. O exemplo mostra como passar IDs e recuperar um em RealmObject
casos de uso comuns do Android.
Objetos congelados
Objetos vivos, confinados ao thread, funcionam bem na maioria dos casos. No entanto, alguns aplicativos -- aqueles baseados em arquiteturas reativas, baseadas em fluxo de eventos, por exemplo -- precisam enviar cópias imutáveis entre threads. Nesse caso, você pode congelar objeto, collection e domínios.
O congelamento cria uma visão imutável de um objeto, collection ou Realm específico que ainda existe no disco e não precisa ser copiado profundamente quando passado para outros segmentos. Você pode compartilhar livremente um objeto congelado entre threads sem se preocupar com problemas de thread.
Objetos congelados não estão ativos e não são atualizados automaticamente. Eles são efetivamente snapshots do estado do objeto no momento do congelamento. Quando você congela um realm, todos os objetos filhos e coleções também ficam congelados. Não é possível modificar objetos congelados, mas você pode ler a chave primária de um objeto congelado, consultar um realm ativo para obter o objeto subjacente e, em seguida, atualizar essa instância de objeto ativo.
Objetos congelados continuam válidos enquanto o realm que os gerou permaneça aberto. Evite fechar realms que contenham objetos congelados até que todas as threads tenham terminado de trabalhar com esses objetos congelados.
Aviso
Exceções de objetos congelados
Quando estiver trabalhando com objetos congelados, uma tentativa de realizar qualquer uma das seguintes ações gera uma exceção:
Abrir uma transação de gravação em um realm congelado.
Modificar um objeto congelado.
Adicionar um ouvinte de alteração a um realm, collection ou objeto congelado.
Depois de congelado, não é possível descongelar um objeto. Você pode utilizar isFrozen()
para verificar se um objeto está congelado. Este método é sempre seguro para threads.
Para congelar um objeto, collection ou realm, use o método query() :
Realm realm = Realm.getInstance(config); // Get an immutable copy of the realm that can be passed across threads Realm frozenRealm = realm.freeze(); Assert.assertTrue(frozenRealm.isFrozen()); RealmResults<Frog> frogs = realm.where(Frog.class).findAll(); // You can freeze collections RealmResults<Frog> frozenFrogs = frogs.freeze(); Assert.assertTrue(frozenFrogs.isFrozen()); // You can still read from frozen realms RealmResults<Frog> frozenFrogs2 = frozenRealm.where(Frog.class).findAll(); Assert.assertTrue(frozenFrogs2.isFrozen()); Frog frog = frogs.first(); Assert.assertTrue(!frog.getRealm().isFrozen()); // You can freeze objects Frog frozenFrog = frog.freeze(); Assert.assertTrue(frozenFrog.isFrozen()); // Frozen objects have a reference to a frozen realm Assert.assertTrue(frozenFrog.getRealm().isFrozen());
val realm = Realm.getInstance(config) // Get an immutable copy of the realm that can be passed across threads val frozenRealm = realm.freeze() Assert.assertTrue(frozenRealm.isFrozen) val frogs = realm.where(Frog::class.java).findAll() // You can freeze collections val frozenFrogs = frogs.freeze() Assert.assertTrue(frozenFrogs.isFrozen) // You can still read from frozen realms val frozenFrogs2 = frozenRealm.where(Frog::class.java).findAll() Assert.assertTrue(frozenFrogs2.isFrozen) val frog: Frog = frogs.first()!! Assert.assertTrue(!frog.realm.isFrozen) // You can freeze objects val frozenFrog: Frog = frog.freeze() Assert.assertTrue(frozenFrog.isFrozen) Assert.assertTrue(frozenFrog.realm.isFrozen)
Importante
objeto congelados e tamanho do Realm
Objeto congelados preservam uma cópia inteira do Realm que os contém no momento em que foram congelados. Como resultado, o congelamento de um grande número de objeto pode fazer com que um Realm consuma mais memória e armazenamento do que poderia sem objeto congelados. Se você precisar congelar separadamente um grande número de objetos por longos períodos de tempo, considere copiar o que você precisa para fora do Realm.
Atualização de Realms
Quando você abre um realm, ele reflete a mais recente confirmação de gravação bem-sucedida e permanece nessa versão até ser atualizado. Isso significa que o realm não verá as mudanças que aconteceram em outro thread até a próxima atualização. Os realms em qualquer thread de loop de eventos (incluindo o thread da UI) se atualizam automaticamente no início do loop desse thread. No entanto, você deve atualizar manualmente as instâncias de realm que estão vinculadas a threads sem loop ou cuja atualização automática está desativada. Para atualizar um domínio, chame Realm.refresh():
if (!realm.isAutoRefresh()) { // manually refresh realm.refresh(); }
if (!realm.isAutoRefresh) { // manually refresh realm.refresh() }
Dica
Atualizar na gravação
Os domínios também são atualizados automaticamente após concluir uma transação de escrita.
Modelo de threading do Realm em detalhes
O Realm fornece acesso seguro, rápido, sem bloqueios e simultâneo em todos os threads com seu MVCC (Multiversion Concurrency Control) arquitetura.
Comparação e contraste com Git
Se você está familiarizado com um sistema de controle de versão distribuído como o Git, talvez já tenha uma compreensão intuitiva do MVCC. Dois elementos fundamentais do Git são:
Confirmações, que são escritas atômicas.
Ramificações, que são versões diferentes do histórico de confirmações.
Da mesma forma, o Realm tem gravações confirmadas atomicamente na forma de transações. O Realm também tem muitas versões diferentes da história a qualquer momento, como ramificações.
Ao contrário do Git, que suporta ativamente a distribuição e a divergência por meio de forking, um Realm só tem uma versão mais recente verdadeira em um determinado momento e sempre escreve para o head dessa versão mais recente. O Realm não pode escrever em uma versão anterior. Isso faz sentido: seus dados devem convergir para uma versão mais recente da verdade.
Estrutura interna
Um domínio é implementado usando uma estrutura de dados B+tree.. O nó de alto nível representa uma versão do domínio; nós secundários são objetos nessa versão do domínio. O domínio tem um ponteiro para sua versão mais recente, assim como o Git tem um ponteiro para sua confirmação de CABEÇALHO.
A Realm usa uma técnica de cópia em gravação para garantir o isolamento e durabilidade . Quando você faz alterações, o Realm copia a parte relevante da árvore para escrever e, em seguida, confirma as alterações em duas fases:
Grave as alterações no disco e verifique o sucesso.
Defina o ponteiro da versão mais recente para o ponto para a versão recém-escrita.
Esse processo de confirmação em duas etapas garante que, mesmo que a gravação falhe parcialmente, a versão original não será corrompida de forma alguma, pois as alterações foram feitas em uma cópia da parte relevante da árvore. Da mesma forma, o ponteiro raiz do domínio apontará para a versão original até que a nova versão seja válida.
Exemplo
O diagrama a seguir ilustra o processo de confirmação:
O realm é estruturado como uma árvore. O realm tem um ponteiro para a sua última versão, V1.
Ao escrever, o Realm cria uma nova versão V2 com base na V1. Realm faz cópias de objetos para modificação (A 1 , C 1), enquanto links para objetos não modificados continuam a apontar para as versões originais (B, D).
Após validar o commit, o Realm atualiza o ponteiro para a nova versão mais recente, V2. O Realm então descarta nós antigos que não estão mais conectados à árvore.
Realm usa técnicas de cópia zero, como mapeamento de memória, para lidar com dados. Quando você lê um valor do realm, você está virtualmente olhando para o valor no disco real, não uma cópia dele. Esta é a base para objetos vivos. É também por isso que um ponteiro de head de realm pode ser definido para apontar para a nova versão depois que a gravação no disco tiver sido validada.
Resumo
O Realm habilita a programação simples e segura de várias threads seguindo três regras:
Evite escritas no thread da UI se escrever em threads em background ou usar a Sincronização.
não passar objetos ativos para outras threads.
Não trave a leitura.
Para ver as alterações feitas em outras threads na sua instância de realm,atualize manualmente as instâncias de realm que não existem nas threads de "loop" ou cuja atualização automática esteja desativada.
Para aplicativos baseados em arquiteturas reativas e em fluxo de eventos, você pode congelar objetos, coleções e domínios para passar cópias de forma eficiente para diferentes threads para processamento.
A arquitetura de controle de concorrência multiversão (MVCC) do Realm é semelhante à do Git. Diferentemente do Git, o Realm possui apenas uma única versão mais recente para cada realm.
O Realm faz confirmações em duas etapas para garantir o isolamento e a durabilidade.