Começando com Android Data Binding

Neste post falarei um pouco sobre a Data Binding Library, um projeto desenvolvido pela Google, e que agora faz parte do Android JetPack, que tem por objetivo facilitar o binding entre os layouts XML e código Java ou Kotlin, evitando assim o famigerado findViewById(). Além disso, utilizando Data Binding é possível dar mais poder aos seus layouts XML e inclusive torná-los observáveis.

A Data Binding Library tira bastante proveito da geração automática de código durante a compilação do projeto, de tal forma que ela gera classes de binding que representa o seu layout XML em código Java.


findViewById()

De um modo geral, sabemos que o desenvolvimento de apps Android é constituído de dois elementos principais: layouts XML e código Java ou Kotlin. Para que possamos associar os layouts XML ao nosso código Java, é necessário fazer o binding dos componentes visuais através do famoso método findViewById(). É a forma básica de fazer isso, porém é extremamente verboso e repetitivo.

Como alternativa para esse problema, existe uma biblioteca bastante conhecida e utilizada que se chama Butter Knife. Com a utilização dessa biblioteca, é possivel realizar o binding entre componentes visuais de uma forma mais fácil, por meio de anotações que a biblioteca fornece, juntamente com a geração automática desses códigos para fazer o binding dos componentes visuais.

Mesmo que a utilização do Butter Knife reduza significativamente a repetição de código, ainda sim existe uma certa repetição em declarar a famosa anotação @BindView para cada atributo que representa um componente do layout XML.

Sem mais delongas, vamos falar neste post como utilizar a biblioteca Data Binding, tirando proveito dos seus poderes e como tornar seu código mais limpo.


Configurando o projeto

Primeiramente, é necessário habilitar a Data Binding no projeto. Para isso, basta adicionar o código abaixo no arquivo build.gradle do módulo do aplicativo:

Caso você queira utilizar em um projeto escrito em Kotlin, terá que adicionar a linha abaixo nas dependências do mesmo arquivo:

Vale a pena lembrar que para usar o kapt é necessário adicionar o plugin kotlin-kapt no seu build.gradle:

Após isso, basta sincronizar o Gradle e fazer um build no projeto pra ver se está tudo ok. Tudo beleza até aqui? :)

Ajustando os layouts

A primeira mudança que é necessária a ser feita é mudar o elemento raiz dos arquivos de layout para <layout>…</layout> e colocar seu layout dentro dessa tag. Com isso, seu layout passará a ser reconhecido pela Data Binding.

Exemplo:

Adicionando a tag <layout> na raiz:

Tranquilo, né? Dessa forma, o nosso layout passará a ser reconhecido e processado pela Data Binding.

Criando nosso playground app

A seguir iremos criar um app bem simples que consistem no cadastro e listagem de contatos, visando exemplificar o uso da Data Binding com uma maior abrangência. O aplicativo será escrito em Kotlin.

Nosso aplicativo terá como principal e único domínio uma classe chamada Contact, que possui as propriedades name, email e phone:

O nosso app terá duas telas, uma para listar os contatos cadastrados e outra para cadastra um novo contato.

O layout a seguir é o layout da tela de listagem de contatos:


Notem que dentro do layout existe um elemento <data>, onde dentro deste elemento é possível realizar import de classes e criação de variáveis dentro do layout.

Desta forma, a classe View estará disponível dentro do layout. Com isso, você poderá utilizar, por exemplo, as constantes `View.GONE` ou `View.VISIBLE`.

E para criar uma váriavel para utilizá-la dentro do layout, basta utilizat a tag <variable> dentro do elemento <data>:

Com isso, as variáveis que você declarou dentro do layout estarão disponíveis e poderão ser utilizadas dentro de expressões da Data Binding, mas vamos exemplificar isso adiante.


Dentro do layout XML é possívei criar expressões que são processadas pela Data Binding e estas expressões são transformadas em código Java. Basicamente, uma expressão pode ser uma chamada a um método ou o acesso a uma váriavel, e essas expressões tem a seguinte sintaxe:

@{ alguma_expressao }

Ela deve estar dentro de uma String e deve começar com um @ e estar dentro de um par de chaves { }.

Tomando o layout da nossa tela de listagem de contatos, podemos observar as seguintes expressões:

A primeira e a segunda linha exemplificam uma expressão na chamada de um método. A primeira expressão nos diz que estamos querendo executar o método startNewContactActivity() da variável viewModel. A segunda expressão nos diz que queremos que o método listAll() da variável viewModel deve ser chamado quando o evento onRefreshListener do nosso SwipeRefreshlayout for disparado. Notem que essa expressão na chamada de um método lembra as expressões lambda introduzidas no Java 8, não é? Adicionalmente, se o listerner do componente a qual você está chamando um método tiver paramêtros, você pode adicionar esses parâmetrod dentro dos parênteses da expressão. Exemplo:

android:onClick=”@{(view) -> foo.bar(view)}”

E na ultima linha nos diz que o nosso SwipeRefreshLayout deve notificar ao usuário se está sendo atualizado ou não de acordo com o valor da propriedade isLoading também da nossa variável viewModel.

O método safeUnbox() faz parte da Data Binding e ele realiza o unboxing de forma segura, verificando se o valor do parâmetro é nulo ou não antes de acessá-lo. Caso o valor seja nulo, ele retorna o valor padrão daquele tipo primitivo.

Abaixo é apresentado o código do adapter do RecyclerView:

O nosso adapter é uma classe Kotlin que recebe uma lista de contatos no construtor primário, onde esta lista representa os contatos que estão salvos no banco de dados do aplicativo.

No método onCreateViewHolder() é instanciado o ViewHolder e o layout que representa as linhas do RecyclerView é inflado. Não se preocupem que o ViewHolder e o layout serão apresentados e explicados logo a seguir.

E o método onBindViewHolder() é responsável por pegar o contato da lista de contatos de acordo com a posição da lista e realizar o binding desse contato dentro do layout que representa os itens do RecyclerView.

O método executePendingBindings() força a classe gerada pela Data Binding a executar algum binding de variáveis que ainda não foram refletidas no layout.

No código a seguir é apresentado o layout de cada linha do RecyclerView:

Note que nesse layout temos uma variável chamada contact do tipo Contact que definimos anteriormente. Este layout possui 3 TextViews que exibem o nome, email e telefone do contato. Para cada TextView está sendo feito o binding das propriedades da váriavel contact. Na linha 28 está sendo feito o binding da propriedade name da variável contact no atributo text do TextView. A mesma coisa se repete nas linhas 41 e 55, onde é feito o binding das propriedades email e phone da variável contact, respectivamente.

Agora será apresentado o código do ViewHolder:

Simples, né? :)

Como a Data Binding gera o código de binding entre código Java / Kotlin e layouts XML, o nosso ViewHolder acaba tendo apenas uma propriedade que representa a classe binding que foi gerada automaticamente a partir do layout XML que representa cada item do RecyclerView que falamos logo acima.

Por fim, o nosso app possui uma tela para cadastrar um novo contato. O layout dessa tela é apresentado a seguir:

Assim como já foi feito anteriormente, esse layout também possui uma variável contact do tipo Contact. A grande diferença nesse layout é que não estamos associando o valor de cada propriedade da nossa variável contact, mas sim preenchendo-os com o que o usuário digita nos campos EditText. Mas como isso é possível? :O

Como você deve ter notado, existe um pequeno detalhe nas expressões do Data Binding nesse layout. Especificamente nas linhas 36, 59 e 82. Só para relembrar, a expressão que foi apresentada anteriormente é:

@{ alguma_expressao }

Porém, as expressões do layout de cadastro de contato tem um caractere a mais, o =. Isso mesmo! Agora a expressão fica dessa forma:

@={ alguma_expressao }

Mas o que significa esse =?

Ele diz para a Data Binding que o valor inserido naquele componente deve ser atribuído a alguém que esteja na expressão. Essa funcionalidade foi inserida na Data Binding algumas releases após o seu lançamento oficial.

Com isso, na linha 36, estamos dizendo para a Data Binding para atribuir o valor que o usuário digitar naquele campo na propriedade name da nossa variável contact. O mesmo se repete nas linhas 59 e 82, onde o valor digitado nos campos serão atribuídos nas propriedades email e phone da variável contact, respectivamente.

Eu, particularmente, acho muito bacana essa funcionalidade da Data Binding de poder atribuir o valor de um componente que está sendo modificado pelo usuário em uma propriedade de um objeto. Isso ajuda a reduzir bastante os códigos para montar objetos a partir dos valores dos campos. Em aplicativos que possuem muitos formulários isso ajuda bastante. Vale ressaltar que isso também se aplica a campos de seleção, como CheckBox por exemplo. :)


E aí, o que você achou?

Os códigos deste artigo foram resumidos para tornar a explicação mais objetiva.

O projeto completo do playground app está disponível no meu Github. Da uma conferida lá! :)

Qualquer dúvida estou à disposição! Até a próxima!

Like what you read? Give Wellington Costa a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.