Что такое Binding и для чего он используется?
View Binding в данном контексте имеет смысл связывания XML элементов layout с атрибутом id в соответствующие View объекты.
В вашем случае, технически это выглядит как генерация класса ActivityPasswordlessBinding , который будет соответствовать вашему layout в сгенерированном классе будут поля именами совпадающими с вашими id задекларированным в layout .
В частности запись: binding.progressBar означает, что в вашем layout видимо есть ProgressBar с идентификатором progressBar
Вопреки комментариям, не имеет прямого отношения к архитектуре ViewModel. ViewModel прекрасно работает и без этого сахара. По сути это разновидность синтаксического сахара (ну чуть-чуть больше чем синтаксический сахар).
До появления view binding приходилось использовать различные ухищрения вроде аннотаций ButterKnife. Сейчас уже рекомендовано с ButterKnife пересаживаться на view binding:
Attention: This tool is now deprecated. Please switch to view binding. Existing versions will continue to work, obviously, but only critical bug fixes for integration with AGP will be considered. Feature development and general bug fixes have stopped.
Урок 19. Android Data Binding. Код в layout. Доступ к View
В этом уроке рассматриваем возможность написания кода в layout и получаем View от биндинга.
Полный список уроков курса:
- Урок 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. Просмотр задачи
Продолжаем говорить про DataBinding. Мы уже рассмотрели, как можно помещать значения из объектов в TextView. Но биндинг этим не ограничивается и дает нам возможность писать код прямо в layout.
Давайте рассмотрим примеры, когда это может понадобиться.
Есть класс Employee:
public class Employee < public Employee(long id, String name, String address, int salary) < this.id = id; this.name = name; this.address = address; this.salary = salary; >public long id; public String name; public String address; public int salary; >
Мы хотим выводить на экран имя, адрес и зарплату.
Экран будет таким:
А вызов биндинга таким:
@Override protected void onCreate(Bundle savedInstanceState)
Ничего необычного. Все так же, как и в прошлом уроке.
Но при запуске получим ошибку: android.content.res.Resources$NotFoundException: String resource ID #0x2710
Так произошло, потому что биндинг попытался отобразить поле salary в TextView. Он просто выполнил код setText(employee.salary). И т.к. salary у нас имеет тип int, то TextView решил, что ему передают идентификатор строкового ресурса. И, конечно, он не нашел такую строку в strings.xml.
Это довольно часто возникающая ошибка. И в коде мы обычно решаем ее с помощью String.valueOf():
textView.setText(String.valueOf(employee.salary));
Биндинг позволяет сделать нам то же самое прямо в layout:
Т.е. внутри @ < . >мы можем писать простейший код и он будет выполнен.
Запустив приложение, мы увидим зарплату в TextView.
Рассмотрим еще несколько примеров:
Отображение в одном TextView сразу двух полей Employee
Обратите внимание на кавычки. Т.к. нам нужны двойные кавычки, чтобы добавить запятую между name и address, то весь этот код мы помещаем в одинарные кавычки.
Видимость View в зависимости от значения поля
" android:visibility="@"/>
Адрес будет отображен, только если он не пустой. А при пустом адресе видимость этого TextView будет GONE.
Обратите внимание, что мы здесь используем классы TextUtils и View. Если сейчас попытаться запустить приложение, то мы получим следующую ошибку: Identifiers must have user defined types from the XML file. TextUtils is missing it
Биндинг говорит, что не знает ничего про TextUtils. Нам надо добавить его в import. Делается это в секции data.
Теперь биндинг знает, какие классы мы имеем ввиду
Т.е. это аналогично тому, как в java коде вы пишете:
import android.text.TextUtils; import android.view.View;
и после этого можете использовать эти классы.
Использование resources значения: strings, dimens и пр.
Если адрес пустой, то показываем заглушку из strings.
В примерах выше мы использовали в layout только одну переменную — Employee. Давайте добавим еще одну.
Создадим новый класс, который будет содержать информацию об отделе
public class Department < public Department(long id, String name) < this.id = id; this.name = name; >public long id; public String name; >
Добавим переменную типа Department в layout
И используем ее:
В одном TextView показываем данные из двух переменных.
Код выполнения биндинга будет выглядеть так:
@Override protected void onCreate(Bundle savedInstanceState)
Для переменной Department в классе MainActivityBinding был сгенерирован отдельный метод setDepartment.
Можно немного усложнить логику и показывать название отдела, только если мы передали объект Department в биндинг:
Показываем отдел, если department не null
Биндинг умеет работать и с коллекциями. Например, если в Employee есть поле со списком хобби:
public List hobbies;
то, в layout мы можем отобразить первое хобби из списка следующим образом:
Если нам необходимо использовать список, как отдельную переменную в layout, то variable будет выглядеть так:
Ограничения XML не позволяют просто так использовать символы < и >. Поэтому их приходится заменять спецсимволами < и >.
То же самое описание переменной, но List вынесен в импорт:
Map коллекции описываются аналогично:
Получение значения по ключу:
В официальной документации вы можете посмотреть полный список возможностей написания кода в layout.
View
Если нам нужны какие-либо View из нашего layout, то их можно получить из биндинга. Для этого необходимо, чтобы View имело id.
Например, если в layout есть поле:
то мы можем получить его из биндинга так:
TextView textViewName = binding.name;
Также можно получить корневое View методом getRoot:
View rootView = binding.getRoot();
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
Урок 8. Android Data Binding – основы
Продолжаем курс по обучению основам разработки мобильных приложений в Android Studio на языке Kotlin. В этом уроке познакомимся с Android Data Binding.
- Data Binding Library
- С чего начать
- Что нам понадобится
- Подключаем Data Binding в проект
- Конвертируем макет в Data Binding
- Обернем макет в тег
- Layout variables и layout expressions
- Создадим layout expression
- Изменим Activity
Data Binding Library
Библиотека Data Binding Library, которая является частью Android Jetpack, позволяет привязывать компоненты пользовательского интерфейса в макетах к источникам данных в приложении, используя декларативный формат, а не программно. Другими словами, Data Binding поможет организовать работу с View так, чтобы нам не пришлось писать кучу методов findViewById, setText, setOnClickListener и т.п.
Чтобы более тесно на практике познакомиться с чистой архитектурой и архитектурными компонентами, записывайтесь на продвинутый курс по разработке приложения «Чат-мессенжер»
В этом цикле уроков вы узнаете, как настроить Data Binding в проекте, что такое layout expressions, как работать с observable objects и как создавать кастомные Binding Adapters чтобы свести избыточность (boilerplate) вашего кода к минимуму.
С чего начать
В этом уроке, мы возьмем уже существующий проект и конвертируем его в Data Binding:

Приложение имеет один экран, который показывает некоторые статические данные и некоторые наблюдаемые данные, что означает, что при изменении данных пользовательский интерфейс будет автоматически обновляться. Данные предоставлены ViewModel. Model-View-ViewModel – это шаблон уровня представления, который очень хорошо работает с Data Binding. Вот диаграмма паттерна MVVM:

Если вы еще не знакомы с классом ViewModel из библиотек компонентов архитектуры, вы можете посмотреть официальную документацию. Мы знакомились с этим классом на прошлом уроке, ссылку на который вы видите в правом верхнем углу этого видео. Это класс, который предоставляет состояние пользовательского интерфейса для представления (Activity, Fragment, т.п.). Он выдерживает изменения ориентации и действует как интерфейс для остальных слоев вашего приложения.
Что нам понадобится
- Среда разработки Android Studio 3.4 или более новой версии.
- Приложение без Data Binding
На этом этапе мы загрузим и запустим простое приложение-пример. Выполните в консоли команду:
$ git clone https://github.com/androidstart/DataBindingSample/tree/master
Вы также можете клонировать или скачать репозиторий в виде Zip-файла по ссылке на GitHub
- Распакуйте проект
- Откройте проект в Android Studio версии 3.4 или выше.
- Запустите приложение
Экран по умолчанию открывается и выглядит так:

Этот экран отображает несколько различных полей и кнопку, по нажатию которой можно увеличить счетчик, обновить индикатор выполнения и изображение. Логика действий, происходящих на экране, описана в классе SimpleViewModel. Откройте его и посмотрите.
Используйте Ctrl + N, чтобы быстро найти класс в Android Studio. Используйте Ctrl + Shift + N, чтобы найти файл по его имени.
На Mac найдите класс с помощью Command + O и файл с помощью Command + Shift + O.
В классе SimpleViewModel описаны такие поля:
- Имя и фамилия
- Количество лайков
- Уровень популярности
Кроме того, он позволяет пользователю увеличивать количество лайков методом onLike().
Пока SimpleViewModel содержит не самый интересный функционал, но здесь все в порядке. С другой стороны, класс главного экрана MainActivity имеет ряд проблем:
- Он вызывает метод findViewById несколько раз. Это не только медленно, но и небезопасно, потому что не проверяется на ошибки времени компиляции. Если идентификатор, который вы передаете в findViewById, неправильный, приложение аварийно завершит работу во время выполнения.
- Устанавливает начальные значения в onCreate. Было бы намного лучше иметь значения по умолчанию, которые устанавливаются автоматически.
- Использует в макете атрибут android:onClick который также не является безопасным: если метод onLike не реализован в активити (или переименован), приложение упадет в рантайме.
- В нем много кода. Активити и фрагменты имеют тенденцию расти очень быстро, поэтому желателно удалить из них как можно больше кода. Кроме того, код в активити и фрагментах трудно тестировать и поддерживать.
В нашей серии уроков с помощью библиотеки Data Binding мы собираемся исправить все эти проблемы, переместив логику из активити в места, где ее можно повторно использовать и проще тестировать.
Подключаем Data Binding в проект
Первым шагом является включение библиотеки Data Binding в модули, которые будут ее использовать. Добавьте такие строки в файл сборки модуля app:
android < . dataBinding < enabled true >>
Конвертируем макет в Data Binding
Откройте файл activity_main.xml. Это обычный макет с Constraint Layout в качестве корневого элемента.
Для того, чтобы преобразовать макет в Data Binding, необходимо:
- Обернуть ваш макет тегом
- Добавить переменные макета (layoutvariables)
- Добавить выражения макета (layoutexpressions)
Обернем макет в тег
Обернем корневой элемент в тег . Нам также придется переместить определения пространства имен (атрибуты, которые начинаются с xmlns:) в новый корневой элемент.
Очень удобно, что Android Studio предлагает способ сделать это автоматически:

Теперь ваш макет должен выглядеть так:
Между тегов мы разместим layout variables.
Layout variables и layout expressions
Переменные макета layout variables используются для записи выражений макета layout expressions. Layout expressions помещаются в значение атрибутов элемента. Для них используют формат записи @ .
Вот несколько примеров:
// Some examples of complex layout expressions android:text="@" android:visibility="@" android:transitionName='@'
Язык layout expressions довольно мощный, но вы должны использовать его только для базовой разметки, потому что более сложные выражения затруднят чтение и поддержку.
// Bind the name property of the viewmodel to the text attribute android:text="@" // Bind the nameVisible property of the viewmodel to the visibility attribute android:visibility="@" // Call the onLike() method on the viewmodel when the View is clicked. android:onClick="@ viewmodel.onLike()>"
С полным описанием языка можно ознакомиться здесь.
Теперь давайте привяжем некоторые данные.
Создадим layout expression
- Начнем с привязки статических данных. Создадим две String layout variables внутри тега .
- Найдем TextView по ID plain_name и добавим атрибут android:text с layout expression:
Выражения макета начинаются с символа @ и заключены в фигурные скобки < >.
Поскольку переменная name имеет тип String, Data Binding будет знать, как установить это значение в TextView. Позже вы узнаете, как обращаться с различными типами и атрибутами выражений макета.
- Сделайте то же самое с текстовым полем plain_lastName:
Теперь нам нужно изменить Activity, чтобы она правильно наполняла макетData Binding.
Изменим Activity
Макет готов, но нам нужно внести некоторые изменения в активити. Откроем MainActivity .
Поскольку мы используем Data Binding layout, наполнение макета происходит другим путем.
В onCreate, замените код определения макета разметки:
setContentView(R.layout.activity_main)
val binding : ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
Почему мы создаем переменную? Потому что нам нужен способ установить переменные макета, которые мы объявили в нашем блоке . Вот для чего предназначен binding object. Связывающие классы создаются библиотекой автоматически. Откройте сгенерированный класс ActivityMainBinding и посмотрите его код, он не сложен. Здесь поля, которые соответствуют элементам разметки, конструкторы, методы доступа, а также методы, которые инфлейтят и привязывают view-компоненты. Имя этого класса формируется автоматически из имени layout файла разметки (т.е. activity_main), плюс слово Binding. ActivityMainBinding все знает о нашем layout: какие View там есть, какие переменные (variable) мы там указывали, и как все это связать друг с другом, чтобы данные из переменных попадали во View.
- Теперь нам просто нужно установить значения переменных:
binding.name = "Your name" binding.lastName = "Your last name"
И это все. Мы просто связали данные с помощью библиотеки.
Теперь мы можем удалить ненужный код:
- Удалите метод updateName(), Data Binding автоматически находит поля по идентификаторам и устанавливает значения.
- Удалите вызов метода updateName() из onCreate().
Теперь вы можете запустить приложение. Имя и фамилия должны измениться.
Возможно, использование биндинга для пары TextView кажется бессмысленным. Но когда таких TextView десятки, то биндинг может избавить вас от написания кучи кода. Кроме того, мы рассмотрели совсем простой случай использования биндинга. На самом деле его возможности гораздо шире. Эти возможности мы рассмотрим в следующих уроках, где продолжим совершенствовать данный проект.
Исходный код измененного проекта здесь
Урок 18. Android Data Binding. Основы
В build.gradle файл модуля в секции android необходимо включить Data Binding:
android < . dataBinding < enabled = true >>
Правильно произносить байндинг , но биндинг звучит проще — буду использовать его.
Data Binding поможет организовать работу с View так, чтобы нам не пришлось писать кучу методов findViewById, setText, setOnClickListener и т.п. Давайте рассмотрим простой пример.
Есть класс Employee, который содержит в себе данные о работнике
public class Employee < public Employee(long id, String name, String address) < this.id = id; this.name = name; this.address = address; >public long id; public String name; public String address; >
поля: id, имя и адрес.
Мы хотим вывести имя и адрес работника на экран main_activity.xml:
Несложная задача. Для этого мы обычно пишем методы findViewById и setText. Тут все понятно.
Давайте рассмотрим, как это же можно сделать с помощью Data Binding.
Вносим изменения в main_activity.xml:
Корневым элементом теперь является , а LinearLayout сместился внутрь него.
В секции data мы объявляем переменную с именем employee. Ее тип — ранее рассмотренный класс Employee. Теперь мы можем использовать эту переменную в атрибутах вьюшек этого layout. В первом TextView, в атрибуте text мы используем employee.name, а в втором TextView — employee.address.
Обратите внимание, что мы не указываем id для View. В этом нет необходимости.
Как вы понимаете, нам остается лишь передать объект Employee в этот layout. И значения этого объекта будут подставлены в соответствующие TextView.
Это делается следующим образом.
public class MainActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); Employee employee = new Employee(1, "John Smith", "London"); MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); binding.setEmployee(employee); >>
Сначала создаем Employee объект.
Затем используем DataBindingUtil. Метод DataBindingUtil.setContentView внутри себя сделает привычный нам setContentView для Activity, а также настроит и вернет объект биндинга MainActivityBinding.
MainActivityBinding — это сгенерированный класс. Имя этого класса берется из имени layout файла (т.е. main_activity), плюс слово Binding. MainActivityBinding все знает о нашем layout: какие View там есть, какие переменные (variable) мы там указывали, и как все это связать друг с другом, чтобы данные из переменных попадали в View.
Метод setEmployee был сгенерирован в классе биндинга, т.к. мы описали переменную employee в layout файле. Этим методом мы передаем биндингу объект Employee. Биндинг возьмет значения employee.name и employee.address и поместит их (методом setText) в соответствующие TextView. Все, как мы и настраивали в layout.

Данные из Employee помещены в TextView.
Сразу хочу заметить, что если мы теперь в коде будем изменять объект Employee, то данные на экране меняться не будут. Они считались один раз и далее не отслеживаются (при такой реализации).
Чтобы экран получил новые данные, надо снова передать биндингу измененный объект Employee:
binding.setEmployee(employee);
Или можно вызывать метод invalidateAll:
binding.invalidateAll();
Биндинг считает новые данные с ранее полученного объекта Employee.
Поля в Employee в этом примере я сделал public. Но вы можете сделать их private и создать для них public get методы.
Возможно, использование биндинга для пары TextView кажется бессмысленным. Но когда таких TextView десятки, то биндинг может избавить вас от написания кучи кода.
Кроме того, мы рассмотрели совсем простой случай использования биндинга. Но его возможности гораздо шире. Например, можно сделать так, чтобы при передаче в атрибут ImageView ссылки на картинку, биндинг запускал Picasso для загрузки этой картинки и помещал результат в ImageView. Или биндинг может сам отслеживать изменения в объекте с данными (в примере выше — это Employee ) и обновлять экран без каких-либо дополнительных методов.
Эти возможности мы рассмотрим в следующих уроках.
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня