В этом уроке разберем, как можно расширить возможности биндинга с помощью Binding Adapter и Binding Conversion. 

 


Полный список уроков курса:


 

 

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, Kotlin, RxJava, Dagger, Тестирование 

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме 




Language

Социальные сети

 

Telegram канал



Android чат в Telegram



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal