Concrete Logo
Hamburger button

Começando com Data Binding

  • Blog
  • 7 de Maio de 2019
Share

Você que acompanha o Blog já deve ter ouvido falar do Android JetPack, um conjunto de componentes, ferramentas e boas práticas de Android que nos ajuda a implementar apps de forma mais rápida, com fácil manutenção e mais testáveis. Se você não ouviu, dá uma olhada neste post da Izabela que tem uma boa introdução sobre o assunto. Neste post, vamos falar um pouco sobre o Data Binding, uma biblioteca que vincula (mapeia) e facilita o binding da lógica e o layout da Activity, e que faz parte do pacote Android Jetpack, mais precisamente da camada de Architecture Components. O Data Binding é uma biblioteca distinta do sistema operacional e pode ser utilizada a partir do Android 2.1 (API 7).

A ferramenta é bastante poderosa, mas neste post vou mostrar só os primeiros passos para utilizá-la. No projeto de exemplo vamos usar a linguagem Kotlin, configurar um projeto inicial e criar um simples formulário. Lembrando que como o foco aqui é um gatilho para dar os primeiros passos nessa biblioteca, então o formulário não vai ter nenhum tipo de validação de campo, requisição ao servidor ou configuração de bancos de dados locais e/ou externos, ok? Se você tiver interesse, o código deste projeto está no meu Github.

Configurando o projeto

Para que o projeto possa suportar essa biblioteca é necessário habilitá-lo, da seguinte forma:

1. Abra o arquivo build.gradle a nível de aplicação (módulo do aplicativo).
2. Dentro do elemento Android, adicione o seguinte elemento:

E pronto 🙂

Após fazer essa pequena alteração e sincronizar, o nosso projeto vai suportar o Data Binding.

Criando nossa classe modelo

Vamos criar nossa classe modelo bastante simples, só para o nosso aprendizado, que vamos nomar de “User”. Nela, vamos colocar os atributos de nome e email. Fica assim:

Criando layout do formulário

Primeiro, vou mostrar o layout XML do formulário sem a implementação da biblioteca.
Nele, vamos ter dois campos de digitação, nome e email:

Agora que criamos nosso formulário, vamos fazer uma pequena alteração. =D

Implementando o Data Binding

Vamos adicionar uma tag chamada layout, que será nossa tag parent(root) do nosso XML. Fica assim:

E é isso! Esse será o layout para podermos usar nossa biblioteca. Em seguida, vamos implementar o elemento data e vou explicar para que serve e como utilizar.

Vamos entender para que servem essas tags que foram adicionadas no layout?

Com essa alteração, será gerada uma classe binding (classe de ligação) automaticamente e que, por padrão, tem a nomenclatura do nome da ViewName + Binding e no final vai gerar uma classe ActivityMainBinding. Mas de onde vem o nome dessa classe? Do layout XML que criamos, activity_main.xml. Ou seja, se criarmos um layout XML chamado de activity_register.xml e fizermos os mesmos procedimentos acima, a biblioteca vai gerar um arquivo chamado ActivityRegisterBinding.

Elemento data

No elemento data é possível inserir imports de classes como, por exemplo, a nossa classe User.
Mas e se você quiser importar outra classe que não seja uma classe modelo, é possível? Sim! Podemos importar, por exemplo, a classe nativa View. Você pode fazer condições para que uma view ou view group seja visível ou não para o usuário. Poderíamos usar as constantes View.Gone, View.VISIBLE e, entre outras coisas, utilizamos a tag import.

Agora que a classe View foi importada podemos fazer uma pequena validação de algum campo.

No exemplo abaixo, no EditText, vou validar se o usuário é adulto e, caso seja, o campo será visível e a propriedade visibility vai receber o valor da constante VISIBLE. Caso não seja, a propriedade recebe o valor GONE e não será visível para o usuário.

 

No elemento data podemos criar variáveis para que sejam utilizadas dentro do nosso layout, com objetos instanciados.

Para isso, devemos usar a tag variable dentro da tag data, na qual temos a propriedade name, que nada mais é do que o nome do objeto que vamos trabalhar dentro do XML. Após dessa alteração, vamos fazer o build do projeto e um método será gerado automaticamente, com um objeto do tipo que será declarado na propriedade como type. É neste objeto que dizemos qual será o tipo dessa variável e passamos a classe ou, para ser mais preciso, todo o caminho no qual a classe se encontra. Para o exemplo, vamos usar a classe modelo que criamos, a User. Segue abaixo o trecho do código:

Depois de termos criado nossa variável, vamos à anotação no elemento para podermos atribuir um valor para ele. Para isso, implementamos uma anotação @={…} na propriedade android:text=”” do elemento. Fican assim:

Note que na anotação e entre as chaves @={} eu chamo a variável user. Nela, declaramos a tag e a utilizamos como um objeto para que possamos acessar seus atributos. Dessa forma, podemos dar um set no campo de digitação ou um get para obter os dados que foram digitados. Note também que após a anotação @ temos o sinal de igual =. Com ele, podemos receber alterações de dados e observar as alterações feitas ou não pelo usuário. Isso é o que chamamos de Two-Way, mas para funcionar devemos criar uma classe binding, com atributos ObservableFields. Mais à frente vamos falar mais sobre isso.

Observação: depois de ter feito essa alteração, em alguns casos o Android Studio não consegue gerar automaticamente essa classe, então é preciso dar um Clean Project e depois um Rebuild Project, ou até mesmo um Invalidate Caches / Restart. Com esses procedimentos as classes serão geradas normalmente.

Vinculação de dados

Depois de todo aquele pequeno processo, vamos para a activity, que vamos vincular ao layout XML.
Para isso, vamos agora inflar o layout utilizando o método setContentView da classe DataBindingUtil que foi gerada quando fizemos a alteração no layout.
Fica assim:

1. Primeiro vamos remover o método padrão da activity setContentView.
2. Depois, criamos uma instância da classe ActivityMainBinding.

 

O setContentView() foi substituído pelo DataBindingUtil.setContentView(), e esse trecho de código é a nova forma de inflarmos o layout XML e fazer a vinculação do layout e o objeto que vamos criar.

Agora que vinculamos a Activity e o layout XML, vamos instanciar um objeto da classe User, passando como parâmetros o nome e email de um usuário qualquer, e em seguida fazer o binding entre eles. =D
Assim:

Note que ao chamar a variável binding chamamos também o método user (em java seria binding.setUser(user)), que é criado automaticamente a partir do name da variável que criamos no layout XML.

Em seguida passamos como parâmetro o objeto user para o método e ele faz toda a mágica acontecer, exibindo os dados nos campos de digitação.

Fica assim:

Observe que os dados do usuário estão no nosso layout e não foi necessário atribuir os dados do objeto user um a um nos elementos da activity, eles foram inseridos automaticamente nas views.

Nos tópicos anteriores vimos como é fácil atribuir os dados de um objeto nos elementos de uma activity, mas será que é possível formar um objeto com os dados da view no momento em que o usuário preenche os campos? Sim! Vamos ver agora como se faz.

Observáveis

Um observável é uma instância da classe Observable, que emite um fluxo de dados e/ou eventos que podemos usar para emitir um dado na view ou executar alguma ação.

Por que usar observáveis? Para tirar da nossa lista de preocupações a criação de um algoritmo de atualização de dados na view.

Tipos de ObservableFields

No Data Binding, podemos trabalhar com os ObservableFields, que como o próprio nome diz, são objetos observáveis e se parecem com um listener que fica observando (ouvindo) alguma mudança de entrada do usuário em um campo da tela. Os tipos de ObservableFields são os seguintes:

– ObservableBoolean
– ObservableByte
– ObservableChar
– ObservableShort
– ObservableInt
– ObservableLong
– ObservableFloat
– ObservableDouble
– ObservableParcelable
– ObservableField

Vamos criar uma classe binding chamada UserBinding na qual será implementado o ObservableField. Ela vai ficar assim:

Por que criar uma classe binding?

Para poder encapsular os tipos em relação à nossa classe modelo. Se na nossa tela tivéssemos mais campos, a classe binding iria “espelhar” os campos como atributos. E também para não precisar usar uma classe modelo, que poderia ter regras de negócios que não seriam necessárias para apenas atualizar dados na view.

​ Por exemplo:

​ Nossa classe binding ficará assim:

import androidx.databinding.ObservableField

Após criar a classe UserBinding, vamos fazer um refactoring na aplicação.

Refactoring

Nossa primeira alteraçãerá no layout XML, no qual vamos alterar o tipo da variável na tag, na propriedade type=”” e, ainda no type, vamos passar a classe binding que criamos.

Assim:

Lembrando que não é necessário fazer alteração no resto do layout, já que a classe UserBinding possui os mesmos atributos que a classe modelo User.

Agora vamos alterar a activity. Não vamos instanciar a classe User, mas sim a classe UserBinding e passar os valores em seus parâmetros.

Fica assim:

– O que fizemos? Passamos para o método binding.user o objeto da classe binding, que antes recebia uma instância da classe User. Note que, para passar um valor para os parâmetros do construtor, instanciamos um ObservableField e entre parênteses passamos o valor desejado do tipo que implementamos na classe binding.

– Note também que os dados foram inseridos normalmente.

Observação: É provável que no momento em que trocarmos o tipo da classe em nosso layout XML, instanciarmos a classe binding na activity e atribuirmos o objeto no método binding.user, a IDE reclame que o tipo de objeto não é compatível com o que o método está querendo receber. Então, é preciso dar um Clean Project e depois um Rebuild Project. Se necessário, até mesmo um Invalidate Caches / Restart.

Agora que fizemos essa alteração no código, que tal testarmos a funcionalidade da alteração de algum dado do EditText, para vermos se ele é alterado no objeto sem a necessidade de setá-lo manualmente?

Para isso, vou adicionar dois TextViews que vão receber o objeto user (aquela variável que criamos no XML) e atribuir nesses elementos. Você vai notar que apenas alterando/digitando os dados do EditText tudo será alterado automaticamente.

1. Implementando os dois TextViews no layout XML (activity_main):

Pronto!
Após termos implementado esses dois elementos estamos prontos para testar e vermos que depois de ter feito alguma alteração em ambos os campos (EditText), o objeto user será atualizado e consequentemente os TextViews também.

Veja abaixo:

Graças ao Observable, atualizamos o objeto e a nossa tela sem a necessidade de chamar cada elemento e setar os dados e até mesmo sem precisar de algum evento de click, por exemplo.

E para obter esse objeto binding, como faríamos? Neste exemplo, vamos obter o objeto depois do click do botão cadastrar. É bastante simples, basta chamar a variável binding que está na activity e chamar o mesmo método a que atribuímos o objeto. Ele servirá como um get().

Criamos um Log apenas para poder exibir os valores. E depois de pressionar o botão, o log foi criado e os dados foram exibidos.

E é possível usar em um Fragment? Mais uma vez… sim! Vamos ver um exemplo.

Fragment com Data Binding

Criei um simples fragment, chamado de MainFragment, e a partir dele vou fazer um pequeno refactoring. Abaixo temos o código da classe e do XML.

Após a criação do fragment, vamos fazer um pequeno refactoring para que possasmos utilizar o Data Binding. Não vou entrar muito em detalhes, pois o conceito é o mesmo da Activity.

Refactoring

Primeiro, vamos fazer aquela alteração no XML que já conhecemos. Fica assim:

Depois de alterar o layout, é necessário buildar o projeto.

Agora vamos alterar o fragment:

Observe que inflamos o layout chamando o método estático inflate() da classe DataBindingUtil, e é a partir dele que fazemos o binding. Esse método retorna uma instância ViewDataBinding do layout inflado. Passamos por parâmetro o LayoutInflater, o arquivo de layout, a ViewGroup e um boolean.

Após ter inflado, chamamos a variável binding e atribuímos uma instância da classe UserBinding, passando nome e email do usuário, como fizemos no exemplo anterior com Activity.

Entretanto, o método onCreateView() precisa de uma View como retorno, e a própria biblioteca tem essa função que retorna essa view, a chamada root. Chamamos esse método a partir da variável binding e atribuímos no return do método onCreateView(). Pronto! Esse foi um pequeno exemplo de como usar a biblioteca com fragment.

E é isso, pessoal!
Vimos neste post os conceitos básicos do Data Binding e o que podemos fazer com ele. Se você quiser saber mais sobre essa library, recomendo dar uma olhada na documentação oficial, aqui.

Lembrando que este projeto está disponível no meu Github. Dá uma olhada lá! =D

Logo eu volto para falar sobre o Data Binding com projetos mais complexos e exemplos práticos. Tem alguma dúvida ou contribuição? Use os campos abaixo. Até a próxima!