Android — MVVM e Databinding

Facilite sua vida com este incrível padrão

O que é?

Resumidamente, é um jeito de apresentar os dados às views. Em outras palavras, é ‘jeito’ específico de apresentar os dados na tela do seu aplicativo.

Porque usar?

O MVVM (sigla para Model-View-ViewModel) é um ‘padrão’ de apresentação, na qual seu programa vai ser dividido em três camadas — no que diz respeito a apresentação dos dados, já que MVVM, MVC e MVP não são arquiteturas, como expliquei em um outro artigo.

A primeira, a View, é a sua activity. Ela simplesmente ‘recebe’ dados de ‘algum lugar’ (veremos mais adiante) e os exibe. Ponto final. Coisas como animações e especificidades do framework Android, como GPS ou permissões, fazem parte dessa camada.

A segunda camada, a Model, simplesmente é a origem dos seus dados que vão ser exibidos na activity/fragment/custom view. Por exemplo, pode ser classes de banco de dados local ou externo, um sharedPrefs ou até dados mockados. As entidades do programa, suas classes base (por exemplo a classe Pessoa), são parte também da camada Model. Então, como já dito, a Model é a camada da ‘origem’ dos seus dados, a camada que vai prover ou ceder os dados à sua aplicação.

A terceira e última camada, a ViewModel, nada mais é que a abstração da sua view. Por exemplo, supondo que você tem uma Activity chamada ‘ActivityLogin’, você terá uma classe LoginViewModel para esse login. Nessa classe, você terá de abstrair o comportamento que a activity está representando. Supondo que a ActivityLogin contenha dois campos de input (nome e email), um botão de confirmar e um dialog de loading, então sua LoginViewModel irá conter duas strings para representar o nome e o email e uma variável booleana para representar o estado do dialog de loading (porque o loading está ‘on’ ou ‘off’). O comportamento do botão, por se tratar de uma ‘ação’, será representado por um método.

O ViewModel conterá, além disso, uma ou mais referências a camada Model. Por exemplo, seu LoginViewModel conterá um objeto do tipo LoginDatabase para você buscar os dados que irá apresentar na tela.

Por fim, vincularemos a View ao ViewModel de tal forma que, quaisquer mudanças que ocorram na camada Model, sua View ficará ciente disso e renderizará os dados.

O que é e porque usar Databinding?

Databinding, em tradução livre, significa ‘vinculação de dados’. No mundo android, significa que a sua camada View ficará ‘observando’ a camada ViewModel (ficará observando o comportamento abstraído na forma de variáveis) em mão dupla e, caso o valor de uma variável mude, a View automaticamente irá renderizar as mudanças. Por exemplo, uma string que tenha seu valor alterado via código, automaticamente irá apresentar seu novo valor na tela do seu aplicativo. O mesmo serve para caso a View mude o valor de, por exemplo, um campo de texto. A variável correspondente a esse campo de texto, que está na ViewModel, será notificada da mudança e terá seu valor automaticamente alterado.

Abaixo, um exemplo gráfico da interação.

Na imagem acima, a camada View vincula (ou mapeia) os componentes visuais no seu respectivo ViewModel. A vinculação de dados ocorre em mão-única (a view somente envia os valores/interações para a viewModel) ou em mão-dupla (a view envia valores e interações e recebe valores da viewModel).

A viewModel, por sua vez, requisita valores para a camada model e aguarda a resposta. Assim que o valor chega para a viewModel, seus valores são automaticamente exibidos na camada view.

Vantagens

  • Programar se torna mais ‘orgânico’ e ‘simples’, já que não há um ‘controlador’ ou um ‘gerente’ de dados, uma vez que são as views que ‘solicitam’ os dados que elas precisam apresentar;
  • Lógica de exibição fica restrita às views;
  • Código mais organizado e clean;
  • Facilidade para leitura e manutenção do código;
  • Reusabilidade dos seus viewsModels;
  • Testabilidade do seu projeto.
  • Em conjunto com bindingAdapters, tudo fica mais fácil ainda.

Pontos interessantes

O ViewModel é DESACOPLADO da View. Em outras palavras, o ViewModel (a camada um ‘nível’, digamos assim, mais interna que a View) jamais sabe QUEM o está utilizando. Dessa forma, você pode REUTILIZAR e TESTAR facilmente sua classe ViewModel. Essa é a razão principal para utilizar o MVVM.

Da mesma forma, é boa prática você depender de abstrações e não de implementações no que diz respeito à ao acesso ao banco de dados. Por exemplo, sua ViewModel conterá um objeto para você ter acesso aos dados (o objeto que representa seu banco). Entretanto, é boa prática fazer uso de uma ‘interface’ na hora de criar uma referência ao banco de dados (isso se chama inversão de dependência, que é um tipo de injeção de dependência).

Exemplos de caso de uso onde programar usando MVVM + databinding se torna uma tarefa muito menos árdua:

  • Validação de campos acontecendo em tempo real (os campos são validados conforme o usuário os digita).
  • Captação de valores de campos de texto de um modo geral, uma vez que há a possibilidade de vinculação em mão-dupla (two-way datadinding).
  • Exibir listas se torna um trabalho muito simples com BindingAdapter, porque basta usar um bindindAdapter como um atributo de um recyclerView (e fazer seu recyclerView ‘observar’ um arrayList na sua ViewModel) que você terá uma lista com poucas (ou nenhuma) linhas de código (claro, desde que você REUSE o seu bindingAdapter).
    -

Como usar?

Primeiramente, devemos ativar o databinding no build.gradle

Agora, criaremos uma classe chamada LoginActivity e seu respectivo layout xml, chamado activity_login.xml

Note que, ao invés de declarar um relative ou linear como base, declararemos um ‘layout’ apenas.

Em seguida, criaremos uma classe chamada LoginViewModel, que será o seu view model e, dentro dele, declararemos a abstração da sua tela de login.

Note que são campos do tipo Observable. Esses campos serão observados pela sua view. Eles devem ser public.

Agora, declararemos os componentes visuais dentro dos limites do componente base, o layout.

Como já criamos o nosso viewModel, o vincularemos a nossa view através do nosso xml. Usaremos o campo data para declarar variáveis dentro do nosso xml.

Agora, o passo mais importante. Vincularemos a variável pública que está dentro do LoginViewModel ao componente visual equivalente. Por exemplo, Abaixo temos os dois campos.

Email
Password

O botão de login será um mero onClick

Login

Seu método, que está na activity, evocará um método que está dentro do LoginViewModel.

Em seguida, configuraremos o que o aplicativo irá fazer assim que o login for clicado.

Basicamente, ele irá validar se os textos não estão vazios e, caso não esteja, irá ativar um diálogo de loading por 1.5 segundos.

Em alguns casos especiais, como o demonstrado abaixo, devemos vincular manualmente via código o comportamento da view na variável que está dentro do view model.

O trecho acima vincula um ouvinte que escuta qualquer mudança na variável chamada loadingState que está dentro do view model.

Por fim, o passo mais importante: vamos vincular de fato a nossa view (activity) ao nosso view model. Note que o objeto binding, do tipo ActivityLoginBinding, é gerado automaticamente pelo Android Studio. O nome dele é gerado com base no nome do seu layout xml (activity_login se torna ActivityLoginBinding).

Depois, basta executar seu projeto, que se encontra neste repositório do Github, e verá os resultados.

Finalizando

Num primeiro momento, parece um esforço desnecessário utilizar esse padrão de apresentação para apenas validar dois simples campos. Entretanto, um aplicativo moderno não faz apena isso. Pensando no mesmo login: um aplicativo moderno valida os campos em tempo real conforme o usuário digita; um aplicativo moderno exibe mensagens (toast, snackbar ou até mesmo views customizadas) diferentes para cada resultado do login (sucesso, erro, sem rede, etc); um aplicativo moderno apresenta animações de transições de fragmentos ou views para cada interação do usuário; um aplicativo moderno salva os dados de login (criptografados, ainda) em bancos de dados locais, por exemplo, ao clicar de um botão do usuário; enfim, um aplicativo moderno faz muitas coisas numa mera tela de login.

Agora, imagine um aplicativo com vários fragmentos, listas, mensagens de erros, estados possíveis de telas, etc. Tudo isso fica muito mais fácil e simples de se fazer utilizando MVVM e Databinding.

O projeto se encontra nesse repositório do github.

Leituras recomendadas