Como criar um ListAdapter usando Kotlin

Um tutorial para a criação de um ListAdapter utilizado para adaptar o objeto de sua lista possibilitando a exibição com o RecyclerView.

Bruno Hensel
Android Dev BR
5 min readJan 26, 2021

--

Photo by NeONBRAND on Unsplash

Quando comecei a trabalhar como desenvolvedor, uma dos primeiros desafios que tive era o de popular alguns dados em uma lista. Me lembro ainda o quanto eu apanhei pra essa “simples” tarefa.

Já que praticamente todo App que existe por aí exibe de alguma forma uma lista, vou compartilhar com vocês o que aprendi ao longo do caminho.

Vamos lá!

RecyclerView

Esse artigo não é precisamente sobre o RecyclerView, mas vale uma breve descrição da utilidade desse ViewGroup.

Normalmente para exibir uma lista no Android nós usamos o RecyclerView, que, bem, recicla a view utilizada para exibir cada elemento, quando um item é rolado para fora do tela, sem a necessidade de criar uma view nova. Então o RecyclerView requisita essas views criadas pelo view holder e as associa ao seu objeto da lista.

Adapter

O que descobri recentemente é que, o adapter nada mais é que um padrão de projeto “design pattern” utilizado para converter uma interface possibilitando seu funcionamento com outra, e não algo exclusivo para o RecyclerView.

Por exemplo, seu objeto -> adapter -> RecyclerView. Pode-se entender, então, que seu objeto foi adaptado para ser possível sua exibição pelo RecyclerView, e para ser possível essa conversão, seu adapter precisa saber os seguintes dados:

  • De quantos itens a lista é composta, utilizado para determinar o final da lista.
  • Como criar um item.
  • Como criar uma nova view.

ListAdapter

O ListAdapter é uma classe que implementa o comportamento padrão de um RecyclerView.Adapter para ter acesso e contar os itens da lista. É necessário também providenciar uma DiffUtil, que é uma classe responsável por calcular a diferença entre duas listas e retornar uma lista atualizada, o algoritmo utilizado para essa operação chama-se: Eugene W. Myers’s difference algorithm.

Vamos à implementação!!!

O ListAdapter é definido conforme se vê no código abaixo, onde, Any é o objeto de sua lista e VH é o view holder, que ainda explicarei.

A implementação é feita da seguinte forma:

No código acima podemos ver que a classe MoviesAdapter extende a classe ListAdapter, nós tivemos também que informar o objeto da lista MovieDto, um ViewHolder MoviesViewHolder e um DiffUtil MoviesAdapter . A implementação do DiffUtil será demonstrada mais abaixo.

Ao extender o ListAdapter, se faz nescessário implementar dois métodos:

  • onCreateViewHolder:

Este método é responsável pela criação de um novo objeto do tipo view holder, sempre que o RecyclerView precisar de um e é implementado da seguinte maneira:

onCreateViewHolder pede 2 argumentos, um ViewGroup, no qual uma nova view é adicionada antes der ser exibida na tela; e um ViewType, que é utilizado que se tem múltiplas e diferentes views no mesmo RecyclerView, como por exemplo um header.

  • onBindViewholder:

Este, por sua vez, é responsável por vincular os dados e usá-los para preencher o layout do view holder, e é implementado da seguinte forma:

onBindViewHolder pede também 2 argumentos, um objeto do tipo view holder, e uma posição do tipo Int. O view holder é a classe responsável por tudo que é relacionado ao gerenciamento das views; e a posição é informada ao view holder para que este exiba o item nessa determinada posição.

Como vimos, o seu adapter precisa de um objeto do tipo view holder, podemos pensar sobre o view holder como a tradução literal nos sugere, um objeto que segura uma view, cada elemento dentro de sua lista é definido pelo view holder. A justificativa para a necessidade do view holder se da pela razão de que o RecyclerView nunca irá interagir diretamente com a sua view. Mas, como é feita a implementação de um ViewHolder?

Vamos à explicação!

Nosso MoviesViewHolder extende o RecyclerView.ViewHolder e encapsula a lógica para junção das views, para criação do próprio view holder e lida com os eventos de cliques, por exemplo nossa função click: (MovieDto) -> Unit.

Isso nos da uma forma mais encapsulada e clean para a criação de novos view holders e de todo o trabalho relacionado ao detalha de inflar a view e qual o layout será exibido.

Por fim implementamos o DiffUtil, e, como já sabemos, esta classe é reponsável por calcular a diferença entre duas listas, e nos devolver uma lista atualizada para exibição dos dados. Aqui utilizamos o ItemCallback que calcula basicamente a diferença entre dois itens em uma lista, desde que os itens em questão não sejam nulos, ressaltando que essa comparação é baseada no hashCode da sua data class.

Ao extender ItemCallback também se faz necessária a implementação de 2 métodos:

  • areItemsTheSame: Este é chamado para verificar se dois objetos representam o mesmo item.
  • areContentsTheSame: Este é utilizado para checar se dois itens tem a mesma data.

A implementação completa desta classe pode ser feita da seguinte forma:

Tenho preferido implementar o DiffUtil dentro de um private companion object para manter tudo dentro da mesma classe.

E por fim, você precisa passar sua lista de objetos para o ListAdapter. Para tanto, em sua Activity ou Fragment, após setar o seu RecyclerView e criar seu Adapter, chame a função submitList(suaLista) no seu adapter.

Aqui está o código completo da implementação do nosso ListAdapter:

TL;DR

O uso do ListAdapter traz benefícios mais nítidos quando trabalhamos com listas que podem ser alteradas em runtime, como por exemplo, a exclusão de um item da lista, pois, a implementação do ListAdapter com o DiffUtil rodará o algoritmo para detectar as mudanças da sua lista em uma Thread secundária e o ListAdapter, como comportamento padrão, implementa uma animação quando um item é adicionado ou removido da lista.

Obrigado por ter lido até aqui.

Nos vemos no próximo post. :D

--

--