0

RecyclerView com BindingAdapters (Android/Kotlin)

Francisco Rasia
Francisco Rasia

🛸Crie listas ainda mais flexíveis usando os BindingAdapters.


Nesse tutorial - o quarto de uma série que explora assuntos relacionados à persistência de dados, LiveData e apresentação como RecyclerView - vamos transformar o layout XML em um data binding layout, vamos aprender a transformar dos dados e a modificar os elementos visuais por meio de Binding Adapters - adaptadores de vinculação - e entender como essas mudanças deixam nosso código mais robusto e fácil de manter. 



🪐Minha RecyclerView funciona perfeitamente, preciso mesmo de um BindingAdapter?

Na maioria dos cenários, não. Como vimos em inúmeros tutoriais, a RecyclerView já possui um Adapter que faz o binding dos dados com as Views dentro dos itens:



Mas essa solução pode criar problemas quando queremos ter diferentes visualizações dos dados: seja por meio de layouts diferentes (grid x linear), seja criando itens especiais como os cabeçalhos e divisores de listas. Nestas situações seria necessário ter vários adapters, um para cada forma de apresentação dos dados.

Isso acontece porque o Adapter precisa ter conhecimento sobre os componentes internos do layout do ViewHolder: cada elemento precisa ser mapeado e, se faltar algum, teremos crashes do aplicativo.


🚀E como o BindingAdapter ajuda?

O BindingAdapter abstrai o layout e os componentes do ViewHolder, fazendo com que o Adapter não tenha conhecimento excessivo sobre os componentes visuais. As referências às Views são substituídas por uma única referência ao binding object, que é derivado da classe da entidade que estamos exibindo na RecyclerView:



Assim, não existe mais uma vinculação rígida entre o Adapter e o layout do ViewHolder, o que permite modificar a forma de apresentação dos dados, inserido ou removendo campos como desejarmos, sem a necessidade de múltiplas versões da classe adapter. Além disso, delegamos a responsabilidade pelas transformações dos dados para o BindingAdapter. Com isso, atendemos tanto o princípio da única responsabilidade quando a Lei de Demeter.


🛸O pulo do gato

Os adaptadores de vinculação são funções de extensão criadas em um arquivo à parte, usando a annotation @BindingAdapter("...") e passando um nome entre os parênteses, que vai ser usado para vincular a View no arquivo XML com a função de extensão correspondente.


🌌Passo-a-passo


1. Verificar se a buildFeature dataBinding está habilitada

Para fazer isso, vamos abrir o arquivo Build.Gradle do módulo do app e verificar o campo buildFeatures. Nós queremos ter a feature `dataBinding` como verdadeira.

buildFeatures {
    viewBinding true
    dataBinding true
  }


2. Transformar o XML do item em um data binding layout

Converter o layout XML do item em um layout do tipo data binding, criando um campo <data>. Dá para fazer manualmente, mas tem um atalho do Android Studio que nos ajuda: colocar o cursor no primeiro elemento do XML, digitar Alt+Enter e selecionar "convert to data binding layout":


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  xmlns:app="http://schemas.android.com/apk/res-auto">

  <data>

  </data>

  <androidx.cardview.widget.CardView //...


3. Adicionar uma variável com o tipo da entidade que vai ser exibida no Item da lista

Adicionar uma variável `entidade` dentro do campo <data> do nosso layout. Começamos declarando uma <variable>, com o nome entidade e do tipo Entidade. Usar o atalho Ctrl + espaço + espaço para autocompletar o FQN da classe.


<data>
  <variable
    name="entidade"
    type="br.com.exemplo.Entidade" />
</data>


4. Atribuir um valor ao atributo entidade do ViewHolder

Atribuir item que está sendo exibido ao atributo `entidade`do ViewHolder, no método `bind()` da classe ViewHolder. Adicionar também o comando `executePendingBindings()` para otimizar a execução e melhorar o desempenho visual da lista.


fun bind(
    item: Entidade,
) {
    with(binding) {
        entidade = item
        executePendingBindings()
    }
}


5. Criar um arquivo BindingUtils.kt

Vamos armazenar nossos BindingAdapters nesse arquivo.


6. Criar um BindingAdapter

Declarar os binding adapters usando a anotação @BindingAdapter. Entre parênteses eu devo passar um rótulo para o valor que vai ser vinculado.

Nesse exemplo, vamos modificar uma View do tipo TextView, então precisamos escrever uma função de extensão para a classe TextView. Vamos atribuir o nome da Entidade ao texto do TextView, usando a sintaxe de acesso a propriedade:

@BindingAdapter("nomeEntidade")
fun TextView.setNomeEntidade(item: Entidade) {
  text = item.nome
}


** A assinatura da função precisa ser compatível com a View que está sendo modificada: TextView, ImageView, Button... e assim por diante. **


Assim, se quisermos criar um BindingAdapter para uma ImageView, a função ficaria:

@BindingAdapter("entidadeIc")
fun ImageView.changeIcon(item: Entidade) {
    setImageResource(
        when (entidade.ehValido) {
            false -> R.drawable.ic_baseline_warning_amber_24
            else -> R.drawable.ic_baseline_check_24
        }
    )
}


** O nome da função de extensão não é importante, pois vamos usar o nome passado entre os parênteses para localizar o BindingAdapter no arquivo XML **


7. Vincular os componentes visuais usando os BindingAdapters

Agora nós vamos usar os adapters que acabamos de criar. No arquivo XML, vamos localizar as TextViews, eliminar o campo `text` e acessar um novo atributo. Lembra que eu falei que o pulo do gato estava lá no nome do BindingAdapter? Agora nós vamos chamar o atributo pelo nome que criamos no adapter, passando a própria variável passwordDto como parâmetro usando a sintaxe `@{ }`. Soa complicado, mas é muito simples:


<TextView
    android:id="@+id/itemNomeTv"
    //..
    nomeEntidade="@{entidade}"
    //.. />


<ImageView
    android:id="@+id/itemEntidadeIc"
    //..
    entidadeIc="@{entidade}"
    //..
    tools:src="@drawable/ic_baseline_check_24" />


Repare que não preciso indicar qual o atributo da entidade vai ser vinculado - basta passar a entidade como parâmetro que o BindingAdapter se encarrega de selecionar e adaptar o atributo correto.


🚀Conclusão

Nesse artigo, nós vimos como empregar os BindingAdapters para ter listas do tipo RecyclerView ainda mais flexíveis e mais fácil de manter no Android com Kotlin.


🎬Tutorial em vídeo:

Vinculação de dados com Binding Adapters para a RecyclerView no Android com Kotlin


📼Vídeos anteriores: 

https://youtu.be/BVKYlepD0r0

https://youtu.be/uhTpMuQa5BM

https://youtu.be/ATbY-ZUWhHE


📷

Photo by Tangerine Chan on Unsplash


0
0

Comentários (4)

1
Maria Santana

Maria Santana

09/08/2021 08:55

Artigo muito bom, Francisco. Estou fazendo um app que recebe dados de uma api e também salva dados do usuário, esse tutorial abriu minha mente!

0
Wellington Santos

Wellington Santos

05/08/2021 15:21

Valeu, eu vou testar isso alterando os projetos que já fiz dos bootcamps

0
Francisco Rasia

Francisco Rasia

05/08/2021 14:43

@Wellington Legal! Esse assunto é bem interessante e não é tão difícil de implementar. Depois que eu aprendi a criar os BindingAdapters adotei como padrão para todos os meus projetos. Fica muito mais fácil de programar as vinculações porque elas ficam centralizadas no arquivo XML e precisamos mexer em menos pontos do código quando tem qualquer alteração. Abs e ótimos estudos!

Francisco

0
Wellington Santos

Wellington Santos

05/08/2021 12:54

Vou salvar isso nos favoritos 😆

Arquiteto, urbanista, desenvolvedor Kotlin, Java & Android e criador em chefe na chicorialabs.com.br

Brasil