В этом уроке разберем, как можно расширить возможности биндинга с помощью Binding Adapter и Binding Conversion.
Полный список уроков курса:
- Урок 1. Lifecycle
- Урок 2. LiveData
- Урок 3. LiveData. Дополнительные возможности
- Урок 4. ViewModel
- Урок 5. Room. Основы
- Урок 6. Room. Entity
- Урок 7. Room. Insert, Update, Delete, Transaction
- Урок 8. Room. Query
- Урок 9. Room. RxJava
- Урок 10. Room. Запрос из нескольких таблиц. Relation
- Урок 11. Room. Type converter
- Урок 12. Room. Миграция версий базы данных
- Урок 13. Room. Тестирование
- Урок 14. Paging Library. Основы
- Урок 15. Paging Library. PagedList и DataSource. Placeholders.
- Урок 16. Paging Library. LivePagedListBuilder. BoundaryCallback.
- Урок 17. Paging Library. Виды DataSource
- Урок 18. Android Data Binding. Основы
- Урок 19. Android Data Binding. Код в layout. Доступ к View
- Урок 20. Android Data Binding. Обработка событий
- Урок 21. Android Data Binding. Observable поля. Двусторонний биндинг.
- Урок 22. Android Data Binding. Adapter. Conversion.
- Урок 23. Android Data Binding. Использование с include, ViewStub и RecyclerView.
- Урок 24. Navigation Architecture Component. Введение
- Урок 25. Navigation. Передача данных. Type-safe аргументы.
- Урок 26. Navigation. Параметры навигации
- Урок 27. Navigation. NavigationUI.
- Урок 28. Navigation. Вложенный граф. Global Action. Deep Link.
- Урок 29. WorkManager. Введение
- Урок 30. WorkManager. Критерии запуска задачи.
- Урок 31. WorkManager. Последовательность выполнения задач.
- Урок 32. WorkManager. Передача и получение данных
- Урок 33. Практика. О чем это будет.
- Урок 34. Практика. TodoApp. Список задач.
- Урок 35. Практика. TodoApp. Просмотр задачи
Binding Adapter
Android Data Binding предоставляет нам возможность вмешиваться в процесс биндинга и самим определять действие, которое будет выполнено при передаче нового значения в какой-либо атрибут View.
Рассмотрим пример, как биндингом можно сделать загрузку изображений из Internet.
Предположим, что у объекта Employee есть поле avatarUrl, в котором находится ссылка на картинку. Используем это поле в биндинге ImageView.
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="employee" type="ru.startandroid.applicationtest003.data.Employee"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{employee.name}"/> <ImageView android:id="@+id/image" android:layout_width="200dp" android:layout_height="200dp" android:scaleType="centerInside" app:url="@{employee.avatarUrl}"/> </LinearLayout> </layout>
Для ImageView мы добавили свой кастомный атрибут url и туда будем передавать значение из avatarUrl.
Если сейчас попытаться запустить приложение, то получим ошибку: Cannot find the setter for attribute 'app:url' with parameter type java.lang.String on android.widget.ImageView.
Биндинг сообщает, что не может найти setter для атрибута app:url. Давайте создадим такой setter.
Создаем статический public метод в любом классе. Можно выделить под это отдельный класс BindingAdapters, например.
@BindingAdapter({"app:url"}) public static void loadImage(ImageView view, String url) { Picasso.get().load(url).into(view); }
В аннотации BindingAdapter указываем атрибут, для которого хотим сделать setter. Первым параметром метода идет ImageView, с которым биндинг будет работать. А вторым параметром придет значение, которое придет атрибут из employee.avatarUrl.
Этот метод будет вызван, когда для app:url будет выполняться биндинг. Мы используем Picasso, чтобы подгрузить картинку в ImageView.
Setter может работать сразу с несколькими атрибутами. Например, добавим drawable, который должен отображаться в случае, если Picasso не удалось загрузить изображение.
<ImageView android:id="@+id/image" android:layout_width="200dp" android:layout_height="200dp" android:scaleType="centerInside" app:url="@{employee.avatarUrl}" app:errorImage="@{@drawable/ic_error}"/>
Добавляем атрибут errorImage и передаем туда drawable.
Создаем Setter-метод:
@BindingAdapter({"app:url", "app:errorImage"}) public static void loadImage(ImageView view, String url, Drawable errorImage) { Picasso.get().load(url).error(errorImage).into(view); }
В аннотации пишем оба своих атрибута, и в параметрах метода указываем, что ожидаем String и Drawable. В Picasso добавляем использование Darawable в методе error.
Conversion
Conversion удобно использовать, если View ожидает один тип данных, а у вас есть другой, и вам надо выполнить конвертацию.
Рассмотрим пример со списком хобби работника:
public class Employee { public List<Hobby> hobbies; }
Hobby - это отдельный класс с полем name.
Мы хотим выводить список хобби одной строкой в TextView.
Если мы сделаем так:
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{employee.hobbies}"/>
То получим ошибку: Cannot find the setter for attribute 'android:text' with parameter type java.util.List<ru.startandroid.application.data.Hobby> on android.widget.TextView
Биндинг сообщает, что не может поместить List<Hobby> в атрибут android:text. Нам надо научить биндинг конвертировать List<Hobby> в String.
Напишем конвертер. Для этого нужен статический метод с аннотацией BindingConversion. На вход этот метод будет принимать List<Hobby>. А на выходе метод должен вернуть String, чтобы TextView смог это значение принять.
@BindingConversion public static String convertHobbiesToString(List<Hobby> hobbies) { StringBuilder sb = new StringBuilder(); for (Hobby hobby: hobbies) { if (sb.length() > 0) sb.append(", "); sb.append(hobby.name); } return sb.toString(); }
В методе просто все значения из списка помещаем в одну строку.
Биндинг найдет этот конвертер, преобразует список в строку и поместит ее в TextView.
Присоединяйтесь к нам в Telegram:
- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня