Visão geral do ViewModel Parte do Android Jetpack.
A classe ViewModel
foi
projetada para armazenar e gerenciar dados relacionados à IU considerando o ciclo de vida. A classe
ViewModel
permite
que os dados sobrevivam às mudanças de configuração, como a rotação da tela.
A estrutura do Android gerencia os ciclos de vida dos controladores de IU, como atividades e fragmentos. A estrutura pode decidir destruir ou recriar um controlador de IU em resposta a determinadas ações do usuário ou eventos do dispositivo que estão completamente fora do seu controle.
Se o sistema destruir ou recriar um controlador de IU, todos os dados
temporários relacionados à IU armazenados nele serão perdidos. Por exemplo, seu app pode incluir uma
lista de usuários em uma das atividades dele. Quando a atividade for recriada para uma
alteração de configuração, a nova atividade precisará buscar novamente a lista de usuários. Para
dados simples, a atividade pode usar o
método onSaveInstanceState()
e restaurar os próprios dados a partir do pacote em
onCreate()
, mas essa abordagem é adequada apenas
para pequenos volumes de dados que podem ser serializados e depois desserializados, não
para volumes potencialmente grandes de dados, como uma lista de usuários ou bitmaps.
Outro problema é que os controladores de IU geralmente precisam fazer chamadas assíncronas que podem levar algum tempo para retornar. O controlador de IU precisa gerenciar essas chamadas e garantir que o sistema as limpe depois de ser destruído, para evitar possíveis vazamentos de memória. Esse gerenciamento requer muita manutenção e, caso o objeto seja recriado para uma alteração de configuração, representa um desperdício de recursos, porque o objeto pode precisar emitir novamente as chamadas já feitas.
Os controladores de IU, como atividades e fragmentos, têm como objetivo principal exibir dados da IU, reagir às ações do usuário ou lidar com a comunicação do sistema operacional, como solicitações de permissão. A exigência de que os controladores de IU também sejam responsáveis pelo carregamento de dados de um banco de dados ou de uma rede acaba tornando a classe pesada. Atribuir responsabilidades excessivas aos controladores de IU pode fazer com que uma única classe precise lidar sozinha com todo o trabalho de um app, em vez de delegar o trabalho para outras classes. Atribuir responsabilidades excessivas aos controladores de IU dessa maneira também dificulta muito os testes.
É mais fácil e eficiente separar a propriedade de dados da visualização da lógica do controlador de IU.
Implementar um ViewModel
Os componentes de arquitetura fornecem
a classe auxiliar ViewModel
para
o controlador de IU responsável por preparar dados para a IU.
Objetos ViewModel
são
retidos automaticamente durante as mudanças de configuração, de modo que os dados retidos
estejam imediatamente disponíveis para a próxima atividade ou instância de fragmento. Por exemplo,
se você precisar exibir uma lista de usuários no app, atribua a
responsabilidade de adquirir e manter a lista de usuários a um
ViewModel
, em vez de
uma atividade ou fragmento, como mostrado pelo exemplo de código a seguir:
Kotlin
class MyViewModel : ViewModel() { private val users: MutableLiveData<List<User>> by lazy { MutableLiveData().also { loadUsers() } } fun getUsers(): LiveData<List<User>> { return users } private fun loadUsers() { // Do an asynchronous operation to fetch users. } }
Java
public class MyViewModel extends ViewModel { private MutableLiveData<List<User>> users; public LiveData<List<User>> getUsers() { if (users == null) { users = new MutableLiveData<List<User>>(); loadUsers(); } return users; } private void loadUsers() { // Do an asynchronous operation to fetch users. } }
Depois, você pode acessar a lista de uma atividade da seguinte maneira:
Kotlin
class MyActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. // Use the 'by viewModels()' Kotlin property delegate // from the activity-ktx artifact val model: MyViewModel by viewModels() model.getUsers().observe(this, Observer<List<User>>{ users -> // update UI }) } }
Java
public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class); model.getUsers().observe(this, users -> { // update UI }); } }
Se a atividade for recriada, ela receberá a mesma instância MyViewModel
que
foi criada pela primeira atividade. Quando a atividade do proprietário estiver concluída, o
framework chamará o método
onCleared()
do objeto
ViewModel
para que ele possa limpar os recursos.
Objetos ViewModel
são
projetados para sobreviver aos instanciamentos específicos de visualizações ou
LifecycleOwners
. Esse
design também significa que é possível escrever testes para cobrir um ViewModel
mais facilmente,
porque ele não conhece os objetos de visualização e
objetos Lifecycle
.
Objetos ViewModel
podem conter
LifecycleObservers
,
como objetos
LiveData
. No entanto,
os objetos ViewModel
nunca podem
observar mudanças nos observáveis com reconhecimento de ciclo de vida,
como os objetos LiveData
.
Se o
ViewModel
precisar do contexto de
Application
, por exemplo, para localizar um serviço do sistema,
ele poderá estender a classe
AndroidViewModel
e ter um construtor que receba o Application
,
já que a classe Application
estende o Context
.
O ciclo de vida de um ViewModel
Objetos ViewModel
têm como escopo o
Lifecycle
transferido para o
ViewModelProvider
ao receber o
ViewModel
. O
ViewModel
permanece na
memória até o Lifecycle
referente ao escopo dele desaparecer permanentemente: no caso de uma atividade, quando ela
termina e, no caso de um fragmento, quando ele é desanexado.
A Figura 1 ilustra os vários estados do ciclo de vida de uma atividade à medida que ela é submetida a
uma rotação e, em seguida, é concluída. A ilustração também mostra a vida útil do ViewModel
ao lado do
ciclo de vida da atividade associada. Este diagrama específico ilustra os estados de
uma atividade. Os mesmos estados básicos se aplicam ao ciclo de vida de um fragmento.
Geralmente, você solicita um
ViewModel
na primeira vez
que o sistema chama o método
onCreate()
de um objeto de atividade. O sistema pode chamar
onCreate()
várias vezes durante a
vida de uma atividade, como quando a tela de um dispositivo é rotacionada. O
ViewModel
existe a partir
do momento em que um
ViewModel
é solicitado pela primeira vez até que
a atividade seja finalizada e destruída.
Compartilhar dados entre fragmentos
É muito comum que dois ou mais fragmentos em uma atividade precisem se comunicar
uns com os outros. Imagine um caso comum de fragmentos de visualização dividida (master-detail
),
em que você tem um fragmento em que o usuário seleciona um item de uma
lista e outro que exibe o conteúdo do item selecionado. Esse
caso nunca é trivial, porque ambos os fragmentos precisam definir certa descrição da interface,
e a atividade do proprietário precisa unir os dois. Além disso,
ambos os fragmentos precisam lidar com o cenário em que o outro fragmento ainda não foi
criado ou não está visível.
Esse ponto problemático comum pode ser resolvido usando
objetos ViewModel
. Esses
fragmentos podem compartilhar um
ViewModel
usando o
escopo de atividade deles para lidar com essa comunicação, conforme ilustrado pelo seguinte
exemplo de código:
Kotlin
class SharedViewModel : ViewModel() { val selected = MutableLiveData<Item>() fun select(item: Item) { selected.value = item } } class MasterFragment : Fragment() { private lateinit var itemSelector: Selector // Use the 'by activityViewModels()' Kotlin property delegate // from the fragment-ktx artifact private val model: SharedViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) itemSelector.setOnClickListener { item -> // Update the UI } } } class DetailFragment : Fragment() { // Use the 'by activityViewModels()' Kotlin property delegate // from the fragment-ktx artifact private val model: SharedViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) model.selected.observe(viewLifecycleOwner, Observer<Item> { item -> // Update the UI }) } }
Java
public class SharedViewModel extends ViewModel { private final MutableLiveData<Item> selected = new MutableLiveData<Item>(); public void select(Item item) { selected.setValue(item); } public LiveData<Item> getSelected() { return selected; } } public class MasterFragment extends Fragment { private SharedViewModel model; public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); itemSelector.setOnClickListener(item -> { model.select(item); }); } } public class DetailFragment extends Fragment { public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); model.getSelected().observe(getViewLifecycleOwner(), item -> { // Update the UI. }); } }
Os dois fragmentos recuperam a atividade que os contém. Dessa forma,
quando os fragmentos receberem o
ViewModelProvider
,
receberão a mesma instância de SharedViewModel
, que tem escopo para essa
atividade.
Essa abordagem oferece os seguintes benefícios:
- A atividade não precisa fazer nada nem saber nada sobre essa comunicação.
- Os fragmentos não precisam conhecer uns aos outros além do
contrato
SharedViewModel
. Se um dos fragmentos desaparecer, o outro continuará funcionando normalmente. - Cada fragmento tem o próprio ciclo de vida e não é afetado pelo ciclo de vida do outro. Se um fragmento substituir o outro, a IU continuará funcionando sem problemas.
Substituir carregadores pelo ViewModel
As classes de carregadores, como o CursorLoader
, geralmente são usadas para
manter os dados na IU de um app em sincronia com um banco de dados. Você pode usar o
ViewModel
, com
algumas outras classes, para substituir o carregador. Usar um
ViewModel
separa seu
controlador de IU da operação de carregamento de dados, o que significa que você terá
menos referências fortes entre as classes.
Em uma abordagem comum do uso de carregadores, um app pode usar um
CursorLoader
para
observar o conteúdo de um banco de dados. Quando um valor no banco de dados é alterado, o
carregador aciona automaticamente um recarregamento dos dados e atualiza a IU:

O ViewModel
funciona com
Room e
LiveData para substituir o carregador.
O ViewModel
garante que
os dados sobrevivam a uma mudança na configuração do dispositivo.
A Room informa seu
LiveData
quando o banco de dados
muda, e o LiveData, por sua vez,
atualiza a IU com os dados revisados.

Usar corrotinas com o ViewModel
O ViewModel
inclui compatibilidade com corrotinas do Kotlin. Para mais informações, consulte
Usar corrotinas do Kotlin com Componentes da arquitetura do Android.
Mais informações
À medida que seus dados se tornam mais complexos, você pode optar por ter uma classe separada apenas
para carregá-los. O objetivo do
ViewModel
é
encapsular os dados de um controlador de IU para permitir que eles sobrevivam às
mudanças de configuração. Para saber mais sobre como carregar, manter e gerenciar dados entre as
mudanças de configuração, consulte
Como salvar estados de IU.
O Guia para arquitetura de apps Android sugere a criação de uma classe de repositório para lidar com essas funções.
Outros recursos
Para ver mais informações sobre a classe ViewModel
, consulte os
recursos a seguir.
Amostras
- Amostra básica do Android Architecture Components (links em inglês)
- Sunflower (link em inglês), um app de jardinagem que ilustra as práticas recomendadas de desenvolvimento com o Android Jetpack.
Codelabs
- Android Room com um View (Java) (Kotlin)
- Codelab de componentes compatíveis com ciclo de vida do Android
Blogs
- ViewModels: exemplo simples (link em inglês)
- ViewModels: Persistence, onSaveInstanceState(), Restoring UI State e Loaders (link em inglês)
- ViewModels e LiveData: Padrões + AntiPadrões (link em inglês)
- Kotlin sem mistério: noções básicas sobre a sintaxe do Shorthand Lambda (link em inglês)
- Kotlin sem mistério: funções de escopo (link em inglês)
- Kotlin sem mistério: quando usar os acessadores personalizados (link em inglês)
- Carregamento de dados de ciclos de vida com o Architecture Components (link em inglês)