Русский
Русский
English
Статистика
Реклама

Android recyclerview mergeadapter

Делаем код в адаптере чище с помощью MergeAdapter

17.10.2020 02:12:24 | Автор: admin
Надоели перегруженные и сложные адаптеры в вашем проекте, напоминающие картинку ниже? Каждый раз, при добавлении нового типа ячейки хочется переписать адаптер для RecyclerView, чтобы код читался проще? Есть множество подходов, чаще всего рекомендуется использовать подход delegate adapter или, например библиотеку для динамического создания списков с различными типами view как groupie о работе с которой вы можете ознакомиться в этой статье. Но сегодня расскажем о новом классе, который поможет инкапсулировать логику вашего адаптера для разных ячеек тем самым соответствовать принципам SOLID.

image

MergeAdapter новый класс, появившейся в recyclerview:1.2.0-alpha02, который позволит объединить несколько адаптеров для отображения в едином RecyclerView. Это позволит инкапсулировать логику для каждой ячейки в своём адаптере, и позволит переиспользовать её в будущем.

Проблема


Начнем с примера. Предположим, у нас есть задача отобразить ленту с двумя типами данных текст с описанием и картинка. Код в методе onCreateViewHolder в самом распространённом случае будет выглядеть так:

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}


Чем это плохо? Минус такой реализации в нарушении принципов DRY и SOLID (single responsibility и open closed). Чтобы в этом убедиться, достаточно добавить два требования: ввести новый тип данных (чекбокс) и еще одну ленту, где будут только чекбоксы и картинки.

Перед нами встает выбор использовать этот же адаптер для второй ленты или создать новый? Независимо от решения, которое мы выберем, нам придется менять код (об одном и том же, но в разных местах). Надо будет добавить новый VIEW_TYPE, новый ViewHolder и отредактировать методы: getItemViewType(), onCreateViewHolder() и onBindViewHolder().

Если мы решим оставить один адаптер, то на этом изменения закончатся. Но если в будущем новые типы данных с новой логикой будут добавляться только во вторую ленту, первая будет иметь лишний функционал, и ее тоже нужно будет тестировать, хотя она не изменялась.

Если решим создать новый адаптер, то будет просто масса дублирующего кода.

Решение


Новый класс MergeAdapter, позволяет комбинировать разные адаптеры для разного вида ячеек. Например, очень частый кейс использования отображать spinner на время загрузки данных в ленте, а если, вдруг произошла ошибка загрузки отображать ячейку с ошибкой в конце ленты.

image

Решением данной задачи, может быть использование MergeAdapter Предположим, у нас есть 3 адаптера:

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


RecyclerView отобразит элементы каждого адаптера последовательно, в том же порядке, в котором переданы в конструктор. Разные адаптеры позволяют разделить логику для разных ячеек в списке. Например, если необходимо добавить заголовок к списку, не нужно реализовывать эту логику в адаптере, который отвечает за отображение главного контента в списке, можно разделить адаптеры, для разных видов ячеек. Такой подход помогает инкапсулировать логику и переиспользовать её в будущем для разных экранов.

image

Отображение загрузки в заголовке или внизу списка.


Для отображения статуса загрузки вверху или внизу списка нужно добавить адаптеры соответственно:
val mergeAdapter = MergeAdapter(headerAdapter, listAdapter, footerAdapter)recyclerView.adapter = mergeAdapter


Верхняя ячейка и нижняя используют тот же layout, ViewHolder и UI логику (отображение статуса загрузки и скрытие). Вообще, достаточно было бы использовать 2 экземпляра одного и того же адаптера для верха и низа списка. Пример можно посмотреть тут или тут

Если кратко, то вот таким простым способом вы можете улучшить код вашего проекта, если вы используете сложный адаптер с различными типами ячеек.
Понравилась статья? Не забудьте присоединиться к нам в Telegram, а на платформе AndroidSchool.ru публикуются полезные материалы для Android-разработчика и современные туториалы.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru