Эта кодовая лаборатория является частью курса Android Kotlin Fundamentals. Вы получите максимальную отдачу от этого курса, если будете последовательно работать с лабораториями кода. Все кодовые лаборатории курса перечислены на целевой странице кодовых лабораторий Android Kotlin Fundamentals .
Введение
В предыдущей кодовой лаборатории вы обновили приложение TrackMySleepQuality для отображения данных о качестве сна в RecyclerView
. Техники, которые вы изучили, когда создавали свой первый RecyclerView
, достаточны для большинства RecyclerViews
, отображающих простые не слишком большие списки. Однако существует ряд методов, которые делают RecyclerView
более эффективным для больших списков и упрощают поддержку и расширение кода для сложных списков и сеток.
В этой лаборатории кода вы строите приложение для отслеживания сна из предыдущей лаборатории кода. Вы узнаете более эффективный способ обновления списка данных о сне и узнаете, как использовать привязку данных с помощью RecyclerView
. (Если у вас нет приложения из предыдущей лаборатории кода, вы можете загрузить начальный код для этой лаборатории кода.)
Что вы уже должны знать
- Создание базового пользовательского интерфейса с использованием действия, фрагментов и представлений.
- Навигация между фрагментами и использование
safeArgs
для передачи данных между фрагментами. - Просматривайте модели, просматривайте фабрики моделей, преобразования и
LiveData
и их наблюдателей. - Как создать базу данных
Room
, создать DAO и определить сущности. - Как использовать сопрограммы для базы данных и других длительных задач.
- Как реализовать базовый
RecyclerView
сAdapter
,ViewHolder
и макетом элемента.
Что вы узнаете
- Как использовать
DiffUtil
для эффективного обновления списка, отображаемогоRecyclerView
. - Как использовать привязку данных с
RecyclerView
. - Как использовать адаптеры привязки для преобразования данных.
Что ты будешь делать
- Создайте приложение TrackMySleepQuality из предыдущей кодовой лаборатории в этой серии.
- Обновите
SleepNightAdapter
, чтобы эффективно обновлять список с помощьюDiffUtil
. - Реализуйте привязку данных для
RecyclerView
с помощью адаптеров привязки для преобразования данных.
Приложение для отслеживания сна имеет два экрана, представленных фрагментами, как показано на рисунке ниже.
Первый экран, показанный слева, имеет кнопки для запуска и остановки отслеживания. На экране показаны некоторые данные о сне пользователя. Кнопка « Очистить » безвозвратно удаляет все данные, которые приложение собрало для пользователя. Второй экран, показанный справа, предназначен для выбора оценки качества сна.
Это приложение спроектировано так, чтобы использовать контроллер пользовательского интерфейса, ViewModel
и LiveData
, а также базу данных Room
для сохранения данных о сне.
Данные о сне отображаются в RecyclerView
. В этой кодовой лаборатории вы DiffUtil
и часть привязки данных для RecyclerView
. После этой кодлабы ваше приложение будет выглядеть точно так же, но будет более эффективным и простым в масштабировании и обслуживании.
Вы можете продолжить использовать приложение SleepTracker из предыдущей лаборатории кода или загрузить приложение RecyclerViewDiffUtilDataBinding-Starter с GitHub.
- При необходимости загрузите приложение RecyclerViewDiffUtilDataBinding-Starter с GitHub и откройте проект в Android Studio.
- Запустите приложение.
- Откройте файл
SleepNightAdapter.kt
. - Изучите код, чтобы ознакомиться со структурой приложения. Обратитесь к приведенной ниже диаграмме для краткого обзора использования
RecyclerView
с шаблоном адаптера для отображения данных о сне пользователю.
- На основе пользовательского ввода приложение создает список объектов
SleepNight
. Каждый объектSleepNight
представляет одну ночь сна, ее продолжительность и качество. -
SleepNightAdapter
список объектовSleepNight
во что-то, чтоRecyclerView
может использовать и отображать. - Адаптер
SleepNightAdapter
создаетViewHolders
, которые содержат представления, данные и метаинформацию для представления ресайклера для отображения данных. -
RecyclerView
используетSleepNightAdapter
для определения количества отображаемых элементов (getItemCount()
).RecyclerView
используетonCreateViewHolder()
иonBindViewHolder()
, чтобы привязать держателей представления к данным для отображения.
Метод notifyDataSetChanged() неэффективен
Чтобы сообщить RecyclerView
, что элемент в списке изменился и нуждается в обновлении, текущий код вызывает notifyDataSetChanged()
в SleepNightAdapter
, как показано ниже.
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}
Однако notifyDataSetChanged()
сообщает RecyclerView
, что весь список потенциально недействителен. В результате RecyclerView
связывает и перерисовывает каждый элемент в списке, включая элементы, которые не видны на экране. Это много ненужной работы. Для больших или сложных списков этот процесс может занять достаточно много времени, чтобы дисплей мерцал или заикался, когда пользователь прокручивал список.
Чтобы решить эту проблему, вы можете сообщить RecyclerView
, что именно изменилось. Затем RecyclerView
может обновлять только те представления, которые изменились на экране.
RecyclerView
имеет богатый API для обновления одного элемента. Вы можете использовать notifyItemChanged()
, чтобы сообщить RecyclerView
, что элемент изменился, и вы можете использовать аналогичные функции для элементов, которые добавляются, удаляются или перемещаются. Вы можете сделать все это вручную, но эта задача будет нетривиальной и потребует довольно много кода.
К счастью, есть лучший способ.
DiffUtil эффективен и делает всю тяжелую работу за вас
В RecyclerView
есть класс DiffUtil
, предназначенный для вычисления различий между двумя списками. DiffUtil
берет старый список и новый список и выясняет, что отличается. Он находит элементы, которые были добавлены, удалены или изменены. Затем он использует алгоритм, называемый разностным алгоритмом Юджина В. Майерса, чтобы определить минимальное количество изменений, которые необходимо внести в старый список для создания нового списка.
Как только DiffUtil
выясняет, что изменилось, RecyclerView
может использовать эту информацию для обновления только тех элементов, которые были изменены, добавлены, удалены или перемещены, что намного эффективнее, чем переделывать весь список.
В этой задаче вы обновите SleepNightAdapter
, чтобы использовать DiffUtil
для оптимизации RecyclerView
для изменений данных.
Шаг 1: Реализуйте SleepNightDiffCallback
Чтобы использовать функциональность класса DiffUtil
, расширьте DiffUtil.ItemCallback
.
- Откройте
SleepNightAdapter.kt
. - Под полным определением класса
SleepNightAdapter
создайте новый класс верхнего уровня с именемSleepNightDiffCallback
, который расширяетDiffUtil.ItemCallback
. ПередайтеSleepNight
в качестве общего параметра.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
- Поместите курсор в имя класса
SleepNightDiffCallback
. - Нажмите
Alt+Enter
(Option+Enter
на Mac) и выберите «Реализовать участников ». - В открывшемся диалоговом окне щелкните левой кнопкой мыши, удерживая клавишу Shift, чтобы выбрать
areItemsTheSame()
иareContentsTheSame()
, затем нажмите OK .
Это создает заглушки внутриSleepNightDiffCallback
для двух методов, как показано ниже.DiffUtil
использует эти два метода, чтобы выяснить, как изменились список и элементы.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
- Внутри
areItemsTheSame()
заменитеTODO
кодом, который проверяет, совпадают ли два переданных элементаSleepNight
,oldItem
иnewItem
. Если элементы имеют одинаковыйnightId
, они являются одним и тем же элементом, поэтому вернитеtrue
. В противном случае вернутьfalse
.DiffUtil
использует этот тест, чтобы определить, был ли элемент добавлен, удален или перемещен.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem.nightId == newItem.nightId
}
- Внутри
areContentsTheSame()
проверьте, содержат лиoldItem
иnewItem
одни и те же данные; то есть равны ли они. Эта проверка на равенство проверит все поля, потому чтоSleepNight
— это класс данных. КлассыData
автоматически определяют для васequals
и несколько других методов. Если междуoldItem
иnewItem
есть различия, этот код сообщаетDiffUtil
, что элемент был обновлен.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem == newItem
}
Распространенным шаблоном является использование RecyclerView
для отображения списка, который изменяется. RecyclerView
предоставляет класс адаптера ListAdapter
, который помогает создать адаптер RecyclerView
, поддерживаемый списком.
ListAdapter
отслеживает список для вас и уведомляет адаптер, когда список обновляется.
Шаг 1. Измените свой адаптер, чтобы расширить ListAdapter
- В файле
SleepNightAdapter.kt
измените сигнатуру классаSleepNightAdapter
на расширениеListAdapter
. - При появлении запроса импортируйте
androidx.recyclerview.widget.ListAdapter
. - Добавьте
SleepNight
в качестве первого аргумента вListAdapter
передSleepNightAdapter.ViewHolder
. - Добавьте
SleepNightDiffCallback()
в качестве параметра в конструктор.ListAdapter
будет использовать это, чтобы выяснить, что изменилось в списке. Готовая подпись классаSleepNightAdapter
должна выглядеть так, как показано ниже.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
- Внутри класса
SleepNightAdapter
удалите полеdata
, включая установщик. Вам это больше не нужно, потому чтоListAdapter
отслеживает список за вас. - Удалите переопределение
getItemCount()
, потому чтоListAdapter
реализует этот метод за вас. - Чтобы избавиться от ошибки в
onBindViewHolder()
, измените переменнуюitem
. Вместо использованияdata
для полученияitem
вызовите методgetItem(position)
, предоставляемыйListAdapter
.
val item = getItem(position)
Шаг 2: Используйте submitList() для обновления списка
Ваш код должен сообщать ListAdapter
, когда доступен измененный список. ListAdapter
предоставляет метод submitList()
, чтобы сообщить ListAdapter
, что доступна новая версия списка. При вызове этого метода ListAdapter
новый список со старым и обнаруживает элементы, которые были добавлены, удалены, перемещены или изменены. Затем ListAdapter
обновляет элементы, отображаемые RecyclerView
.
- Откройте
SleepTrackerFragment.kt
. - В
onCreateView()
в обозревателеsleepTrackerViewModel
найдите ошибку, в которой содержится ссылка на удаленную вами переменнуюdata
. - Замените
adapter.data = it
вызовомadapter.submitList(it)
. Обновленный код показан ниже.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
- Запустите свое приложение. Он работает быстрее, может быть, незаметно, если ваш список невелик.
В этой задаче вы используете ту же технику, что и в предыдущих лабораторных работах, для настройки привязки данных и исключаете вызовы findViewById()
.
Шаг 1. Добавьте привязку данных к файлу макета.
- Откройте файл макета
list_item_sleep_night.xml
на вкладке « Текст ». - Поместите курсор на тег
ConstraintLayout
и нажмитеAlt+Enter
(Option+Enter
на Mac). Откроется меню намерения (меню «быстрого исправления»). - Выберите Преобразовать в макет привязки данных . Это оборачивает макет в
<layout>
и добавляет внутрь тег<data>
. - При необходимости прокрутите вверх и внутри
<data>
объявите переменную с именемsleep
. - Сделайте его
type
полным именемSleepNight
,com.example.android.trackmysleepquality.database.SleepNight
. Готовый<data>
должен выглядеть так, как показано ниже.
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>
- Чтобы принудительно создать объект
Binding
, выберите Build > Clean Project , затем выберите Build > Rebuild Project . (Если у вас все еще есть проблемы, выберите File > Invalidate Caches/Restart .) Объект привязкиListItemSleepNightBinding
вместе со связанным кодом добавляется в созданные файлы проекта.
Шаг 2. Расширьте макет элемента с помощью привязки данных
- Откройте
SleepNightAdapter.kt
. - В классе
ViewHolder
найдите методfrom()
. - Удалите объявление переменной
view
.
Код для удаления :
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
- Там, где была переменная
view
, определите новую переменную с именемbinding
, которая расширяет объект привязкиListItemSleepNightBinding
, как показано ниже. Сделайте необходимый импорт объекта привязки.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
- В конце функции вместо возврата
view
возвращайтеbinding
.
return ViewHolder(binding)
- Чтобы избавиться от ошибки, поместите курсор на
binding
слова. НажмитеAlt+Enter
(Option+Enter
на Mac), чтобы открыть меню намерений.
- Выберите Изменить тип параметра «itemView» основного конструктора класса «ViewHolder» на «ListItemSleepNightBinding» . Это обновляет тип параметра класса
ViewHolder
.
- Прокрутите вверх до определения класса
ViewHolder
, чтобы увидеть изменения в подписи. Вы видите ошибку дляitemView
, потому что вы изменилиitemView
наbinding
в методеfrom()
.
В определении классаViewHolder
щелкните правой кнопкой мыши одно из вхожденийitemView
и выберите Refactor > Rename . Измените имя наbinding
. - Добавьте к
binding
параметра конструктора префиксval
, чтобы сделать его свойством. - В вызове родительского класса
RecyclerView.ViewHolder
измените параметр сbinding
наbinding.root
. Вам нужно передатьView
, аbinding.root
— это корневойConstraintLayout
в макете вашего элемента. - Готовое объявление класса должно выглядеть так, как показано ниже.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){
Вы также видите ошибку для вызовов findViewById()
и исправляете ее дальше.
Шаг 3: Замените findViewById()
Теперь вы можете обновить sleepLength
, quality
и qualityImage
, чтобы использовать объект binding
вместо findViewById()
.
- Измените инициализацию
sleepLength
,qualityString
иqualityImage
, чтобы использовать представления объектаbinding
, как показано ниже. После этого ваш код больше не должен показывать ошибок.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage
Имея объект привязки, вам больше не нужно определять sleepLength
, quality
и qualityImage
. DataBinding
будет кэшировать поиск, поэтому нет необходимости объявлять эти свойства.
- Щелкните правой кнопкой мыши
sleepLength
,quality
иqualityImage
. Выберите Refactor > Inline или нажмитеControl+Command+N
(Option+Command+N
на Mac). - Запустите свое приложение. (Возможно, вам придется очистить и перестроить ваш проект, если в нем есть ошибки.)
В этой задаче вы обновите свое приложение, чтобы использовать привязку данных с адаптерами привязки для установки данных в представлениях.
В предыдущей кодовой лаборатории вы использовали класс Transformations
для получения LiveData
и создания форматированных строк для отображения в текстовых представлениях. Однако, если вам нужно связать разные типы или сложные типы, вы можете предоставить адаптеры привязки, чтобы помочь привязке данных использовать эти типы. Адаптеры привязки — это адаптеры, которые берут ваши данные и адаптируют их во что-то, что привязка данных может использовать для привязки представления, например текста или изображения.
Вы собираетесь реализовать три адаптера привязки, один для качественного изображения и по одному для каждого текстового поля. Таким образом, чтобы объявить адаптер привязки, вы определяете метод, который принимает элемент и представление, и аннотируете его с помощью @BindingAdapter
. В теле метода вы реализуете преобразование. В Kotlin вы можете написать адаптер привязки как функцию расширения класса представления, который получает данные.
Шаг 1. Создайте адаптеры привязки
Обратите внимание, что вам придется импортировать несколько классов на шаге, и они не будут вызываться по отдельности.
- Откройте
SleepNightAdapater.kt
. - Внутри класса
ViewHolder
найдите методbind()
и напомните себе, что этот метод делает. Вы возьмете код, который вычисляет значения дляbinding.sleepLength
,binding.quality
иbinding.qualityImage
, и вместо этого будете использовать его внутри адаптера. (На данный момент оставьте код как есть; вы переместите его на более позднем этапе.) - В пакете
sleeptracker
создайте и откройте файлBindingUtils.kt
. - Объявите функцию расширения в
TextView
с именемsetSleepDurationFormatted
и передайтеSleepNight
. Эта функция будет вашим адаптером для расчета и форматирования продолжительности сна.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
- В теле
setSleepDurationFormatted
привяжите данные к представлению, как вы делали это вViewHolder.bind()
. ВызовитеconvertDurationToFormatted()
, а затем установитеtext
TextView
в отформатированный текст. (Поскольку это функция расширенияTextView
, вы можете получить прямой доступ кtext
свойству.)
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
- Чтобы сообщить привязку данных об этом адаптере привязки, аннотируйте функцию с помощью
@BindingAdapter
. - Эта функция является адаптером для атрибута
sleepDurationFormatted
, поэтому передайтеsleepDurationFormatted
в качестве аргумента@BindingAdapter
.
@BindingAdapter("sleepDurationFormatted")
- Второй адаптер устанавливает качество сна на основе значения в объекте
SleepNight
. Создайте функцию расширения с именемsetSleepQualityString()
дляTextView
и передайтеSleepNight
. - В теле привяжите данные к представлению, как вы делали это в
ViewHolder.bind()
. ВызовитеconvertNumericQualityToString
и установитеtext
. - Аннотируйте функцию с помощью
@BindingAdapter("sleepQualityString")
.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
- Третий адаптер привязки устанавливает изображение в виде изображения. Создайте функцию расширения в
ImageView
, вызовитеsetSleepImage
и используйте код изViewHolder.bind()
, как показано ниже.
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}
Шаг 2. Обновите SleepNightAdapter
- Откройте
SleepNightAdapter.kt
. - Удалите все в методе
bind()
, потому что теперь вы можете использовать привязку данных и ваши новые адаптеры, чтобы сделать эту работу за вас.
fun bind(item: SleepNight) {
}
- Внутри
bind()
назначьте сонitem
, потому что вам нужно сообщить объекту привязки о вашем новомSleepNight
.
binding.sleep = item
- Ниже этой строки добавьте
binding.executePendingBindings()
. Этот вызов представляет собой оптимизацию, которая запрашивает привязку данных для немедленного выполнения любых ожидающих привязок. Всегда рекомендуется вызыватьexecutePendingBindings()
, когда вы используете адаптеры привязки вRecyclerView
, потому что это может немного ускорить изменение размеров представлений.
binding.executePendingBindings()
Шаг 3. Добавьте привязки к XML-макету
- Откройте
list_item_sleep_night.xml
. - В
ImageView
добавьте свойствоapp
с тем же именем, что и у адаптера привязки, который задает изображение. Передайте переменнуюsleep
, как показано ниже.
Это свойство создает соединение между представлением и объектом привязки через адаптер. Всякий раз, когда ссылаются наsleepImage
, адаптер адаптирует данные изSleepNight
.
app:sleepImage="@{sleep}"
- Сделайте то же самое для текстовых представлений
sleep_length
иquality_string
. Всякий раз, когда ссылаются наsleepDurationFormatted
илиsleepQualityString
, адаптеры будут адаптировать данные изSleepNight
.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
- Запустите свое приложение. Он работает точно так же, как и раньше. Адаптеры привязки берут на себя всю работу по форматированию и обновлению представлений по мере изменения данных, упрощая
ViewHolder
и придавая коду гораздо лучшую структуру, чем раньше.
Вы показали один и тот же список для последних нескольких упражнений. Это задумано, чтобы показать вам, что интерфейс Adapter
позволяет создавать код разными способами. Чем сложнее ваш код, тем важнее его правильно спроектировать. В рабочих приложениях эти и другие шаблоны используются с RecyclerView
. Все шаблоны работают, и у каждого есть свои преимущества. Какой из них вы выберете, зависит от того, что вы строите.
Поздравляю! На данный момент вы уже на пути к освоению RecyclerView
на Android.
Проект Android Studio: RecyclerViewDiffUtilDataBinding .
DiffUtil
:
- В
RecyclerView
есть классDiffUtil
, предназначенный для вычисления различий между двумя списками. -
DiffUtil
имеет классItemCallBack
, который вы расширяете, чтобы выяснить разницу между двумя списками. - В классе
ItemCallback
вы должны переопределитьareItemsTheSame()
иareContentsTheSame()
.
ListAdapter
:
- Чтобы бесплатно управлять списками, вы можете использовать класс
ListAdapter
вместоRecyclerView.Adapter
. Однако, если вы используетеListAdapter
, вам нужно написать свой собственный адаптер для других макетов, поэтому в этой лаборатории кода показано, как это сделать. - Чтобы открыть меню намерений в Android Studio, поместите курсор на любой элемент кода и нажмите
Alt+Enter
(Option+Enter
на Mac). Это меню особенно полезно для рефакторинга кода и создания заглушек для реализации методов. Меню контекстно-зависимое, поэтому вам нужно точно поместить курсор, чтобы получить правильное меню.
Привязка данных:
- Используйте привязку данных в макете элемента для привязки данных к представлениям.
Адаптеры для привязки:
- Ранее вы использовали
Transformations
для создания строк из данных. Если вам нужно привязать данные разных или сложных типов, предоставьте адаптеры привязки, чтобы помочь привязке данных использовать их. - Чтобы объявить адаптер привязки, определите метод, который принимает элемент и представление, и аннотируйте метод с помощью
@BindingAdapter
. В Kotlin вы можете написать адаптер привязки как функцию расширения дляView
. Передайте имя свойства, которое адаптирует адаптер. Например:
@BindingAdapter("sleepDurationFormatted")
- В макете XML задайте свойство
app
с тем же именем, что и у адаптера привязки. Передайте переменную с данными. Например:
.app:sleepDurationFormatted="@{sleep}"
Удасити курсы:
Документация для разработчиков Android:
- Создайте список с помощью RecyclerView
-
RecyclerView
-
DiffUtil
- Библиотека привязки данных
- Адаптеры для привязки
-
notifyDataSetChanged()
-
Transformations
Другие источники:
В этом разделе перечислены возможные домашние задания для студентов, которые работают с этой кодовой лабораторией в рамках курса, проводимого инструктором. Инструктор должен сделать следующее:
- При необходимости задайте домашнее задание.
- Объясните учащимся, как сдавать домашние задания.
- Оценивайте домашние задания.
Преподаватели могут использовать эти предложения так мало или так часто, как они хотят, и должны свободно давать любые другие домашние задания, которые они считают подходящими.
Если вы работаете с этой кодовой лабораторией самостоятельно, не стесняйтесь использовать эти домашние задания, чтобы проверить свои знания.
Ответьте на эти вопросы
Вопрос 1
Что из следующего необходимо для использования DiffUtil
? Выбрать все, что подходит.
▢ Расширить класс ItemCallBack
.
▢ Переопределить areItemsTheSame()
.
▢ Переопределить areContentsTheSame()
.
▢ Используйте привязку данных для отслеживания различий между элементами.
Вопрос 2
Что из следующего верно в отношении адаптеров привязки?
▢ Адаптер привязки — это функция с аннотацией @BindingAdapter
.
▢ Использование адаптера привязки позволяет отделить форматирование данных от держателя представления.
▢ Вы должны использовать RecyclerViewAdapter
, если хотите использовать адаптеры привязки.
▢ Адаптеры привязки — хорошее решение, когда вам нужно преобразовать сложные данные.
Вопрос 3
Когда следует рассмотреть возможность использования Transformations
вместо адаптера привязки? Выбрать все, что подходит.
▢ Ваши данные просты.
▢ Вы форматируете строку.
▢ Ваш список очень длинный.
▢ Ваш ViewHolder
содержит только одно представление.
Начать следующий урок: