Я решил написать эту статью, т.к. заметил, что многие разработчики допускают ошибки при использовании RecyclerView
, даже несмотря на то, что Google уже довольно давно его выпустила.
Описанные здесь пункты упоминались в различных докладах и материалах на Google Devs.
В этой статье я буду кратко описывать ключевые пункты из этого видео, и вам не обязательно смотреть его прямо сейчас. Но рекомендую посмотреть его целиком после прочтения статьи.
1. Атрибут setHasFixedSize
Установите атрибут recyclerView.setHasFixedSize(true)
, когда recyclerView
не планирует изменять размеры своих дочерних элементов динамически.
В результате recyclerView
не будет перерисовываться каждый раз, когда в элементе списка обновятся данные, этот элемент перерисуется самостоятельно.
2. Click listener
Устанавливайте обработчик кликов в onCreateViewHolder(...)
.
Всякий раз, когда пользователь кликает по элементу списка, viewHolder
сообщает позицию адаптера, где этот клик произошёл (vh.getAdapterPosition()
). Это важно, потому что элементы могут перемещаться внутри адаптера, и связанные с ними view
-компоненты не будут пересоздаваться.
В результате к тому времени, когда view
-компонент будет создан, может произойти следующее: элемент списка будет находиться, допустим, на позиции 2, но когда пользователь кликнет на него, элемент будет уже на позиции 5. Таким образом, использование метода vh.getAdapterPosition()
гарантирует получение корректного индекса списка.
3. Использование различных типов view-компонентов
Возвращайте напрямую layout
в случае использования различных типов view
-компонентов (например, R.layout.view_one
).
Если ваш адаптер поддерживает различные типы view
-компонентов, то метод getItemViewType
и onCreateViewHolder
будут выглядеть приблизительно так, как изображено ниже. Вам необходимо написать оператор switch
внутри метода onCreateViewHolder
для реализации нужной логики для соответствующих типов view
-компонентов.
Но вместо этих типов, вы можете вернуть сразу layout
. Это избавит вас от шаблонного кода в onCreateViewHolder
:
Этот приём нельзя использовать постоянно, т.к. иногда вам может потребоваться более сложная логика внутри каждого выбранного layout
для разных случаев. Но если это не ваш случай, то возвращаемые layout
— это верный путь для работы с различными типами view
-компонентов.
4. DiffUtil
Используйте DiffUtil
для добавления новых данных в RecyclerView
.
Всякий раз, когда данные в recyclerView
меняются, большинство разработчиков вызывают метод notifyDataSetChanged()
для отображения обновлённых данных на UI. Они просто не знают, что данный метод ресурсозатратен, и что именно здесь DiffUtil
справляется куда эффективнее.
DiffUtil
— это класс-утилита, который может вычислять разницу между двумя списками в виде списка обновлений, который затем конвертирует первый список во второй. Его можно использовать для вычисления обновлений в адаптере recyclerView
. Чтобы использовать DiffUtil
, вы должны реализовать DiffUtil.Callback
, в котором есть несколько обязательных методов, необходимых для реализации логики DiffUtil
:
Самое большое преимущество DiffUtil
заключается в том, что в RecyclerView
вы можете обновить конкретный текст в TextView
определённого элемента, вместо того, чтобы перерисовывать весь список. Для этого вам необходимо реализовать метод onChangePayload
в DiffUtil.Callback
. Есть очень хорошая статья на эту тему.
Во второй части рассмотрим другие советы качественного использования RecyclerView
.
Комментарии (5)
dmlukas
19.10.2018 13:04Вмест DiffUtil можно использовать из коробки ListAdapter, хотя там тоже надо переопределить колбэк.
ilitaexperta
Советы по профессиональному использованию кривого мелкого кусочка API? Чиво?
Скорее пробивает очередное дноИз вашего паблика вк:
Как же гуглоразрабы встаки любят костыли. Почему DiffUtil идет каким-то отдельным говноклассом а не прозрачно реализована внутри того же notifyDataSetChanged?
adarash
Для статьи действительно подошло бы немного другое название.
Но я не понимаю вашей агрессии. Google дает возможности подключения разного рода фич. А дальше разработчики сами решают нужны они или нет.
Или вы считаете, что следует сразу напихать все в базовый класс? Судя по вашему комментарию вы, наверное, сразу всю библиотеку google play services подключаете к проекту.
ilitaexperta
Когда система перекладывает на разработчика реализацию части своего функционала, это говняный дизайн системы. Потому что в текущем виде разрабы не будут заморачиваться с DiffUtil, они просто сделают тормозное приложение и все, а вам потом этим пользоваться
adarash
Позвольте с вами не согласится. Все познается в сравнении. Вот ListView без ViewHolder вот это действительно тормознутый списочек. А RecyclerView без DiffUtil… Разница, на малых объемах данных, не заметна.