Tornando o código do adaptador mais limpo com MergeAdapter

Cansado dos adaptadores sobrecarregados e complexos em seu projeto, como a imagem abaixo? Cada vez que você adiciona um novo tipo de célula, deseja reescrever o adaptador para o RecyclerView para tornar o código mais fácil de ler? Existem muitas abordagens; na maioria das vezes, é recomendável usar a abordagem do adaptador de delegado ou, por exemplo, uma biblioteca para criar listas dinamicamente com diferentes tipos de visualizações, como uma groupie, com a qual você pode se familiarizar neste artigo . Mas hoje falaremos sobre uma nova classe que ajudará a encapsular a lógica do seu adaptador para diferentes células, obedecendo assim aos princípios SOLID.



imagem



MergeAdapter é uma nova classe introduzida em recyclerview: 1.2.0-alpha02 que permite combinar vários adaptadores de vídeo em um único RecyclerView. Isso permitirá que você encapsule a lógica para cada célula em seu adaptador e permitirá que você a reutilize no futuro.



Problema



Vamos começar com um exemplo. Suponha que temos a tarefa de exibir um feed com dois tipos de dados - um texto com uma descrição e uma imagem. O código no método onCreateViewHolder no caso mais comum será parecido com este:



override fun onCreateViewHolder(
    parent: ViewGroup, viewType: Int
): RecyclerView.ViewHolder? {
    val holder: RecyclerView.ViewHolder
    val inflater = LayoutInflater.from(parent.context)
    when (viewType) {
        TEXT_VIEW_TYPE -> {
            holder = TextViewHolder(
                inflater.inflate(R.layout.text_item, parent, false)
            )
        }
        IMAGE_VIEW_TYPE -> {
            holder = ImageViewHolder(
                inflater.inflate(R.layout.image_item, parent, false),
                imageClickListener
            )
        }
        else -> {
            throw IllegalArgumentException(
                "Can't create view holder from view type $viewType"
            )
        }
    }
    return holder
}


Por que isso é ruim? A desvantagem desta implementação é a violação dos princípios de SECO e SÓLIDO (responsabilidade única e aberto fechado). Para ter certeza disso, basta adicionar dois requisitos: inserir um novo tipo de dado (checkbox) e mais uma fita, onde haverá apenas checkboxes e imagens.



Estamos diante de uma escolha - usar o mesmo adaptador para a segunda fita ou criar um novo? Independentemente da solução que escolhermos, teremos que alterar o código (quase a mesma coisa, mas em lugares diferentes). Será necessário adicionar um novo VIEW_TYPE, ViewHolder novos e editar métodos: getItemViewType(), onCreateViewHolder() onBindViewHolder().



Se decidirmos manter um adaptador, as alterações terminarão aí. Mas se no futuro novos tipos de dados com nova lógica forem adicionados apenas ao segundo feed, o primeiro terá funcionalidade extra e também precisará ser testado, embora não tenha mudado.



Se decidirmos criar um novo adaptador, haverá muitos códigos duplicados.



Decisão



A nova classe MergeAdapter permite combinar diferentes adaptadores para diferentes tipos de células. Por exemplo, um caso de uso muito comum é exibir um botão giratório ao carregar dados no feed e, se, de repente, ocorrer um erro de carregamento, exibir uma célula com um erro no final do feed.



imagem



A solução para este problema pode ser o uso de MergeAdapter. Suponha que temos 3 adaptadores:




val firstAdapter: FirstAdapter = …
val secondAdapter: SecondAdapter = …
val thirdAdapter: ThirdAdapter = …val mergeAdapter = MergeAdapter(firstAdapter, secondAdapter, thirdAdapter)
recyclerView.adapter = mergeAdapter


O RecyclerView exibirá os itens de cada adaptador sequencialmente, na mesma ordem em que foram passados ​​para o construtor. Adaptadores diferentes permitem separar a lógica para células diferentes na lista. Por exemplo, se você precisa adicionar um título à lista, você não precisa implementar esta lógica no adaptador, que é responsável por exibir o conteúdo principal da lista, você pode separar os adaptadores para diferentes tipos de células. Essa abordagem ajuda a encapsular a lógica e reutilizá-la no futuro para diferentes telas.



imagem



Exiba o download no cabeçalho ou no final da lista.



Para exibir o status do download na parte superior ou inferior da lista, adicione adaptadores, respectivamente:



val mergeAdapter = MergeAdapter(headerAdapter, listAdapter, footerAdapter)
recyclerView.adapter = mergeAdapter


A célula superior e a inferior usam o mesmo layout, ViewHolder e lógica da IU (mostrar o status de carregamento e ocultar). Em geral, seria suficiente usar 2 instâncias do mesmo adaptador para o início e o fim da lista. Um exemplo pode ser encontrado aqui ou aqui .



Resumindo, de forma simples você pode melhorar o código do seu projeto se usar um adaptador complexo com diferentes tipos de células.



Você gostou do artigo? Não se esqueça de se juntar a nós no Telegram e na plataforma AndroidSchool.ru , materiais úteis para desenvolvedores Android e tutoriais modernos são publicados.



All Articles