Привязка представлений Часть Android Jetpack.
Привязка представлений – это функция, которая упрощает написание кода, взаимодействующего с представлениями. После включения привязки представлений в модуле генерируется класс привязки для каждого XML-файла макета, присутствующего в этом модуле. Экземпляр класса привязки содержит прямые ссылки на все представления, у которых есть идентификатор в соответствующем макете.
В большинстве случаев привязка представлений заменяет findViewById.
Настроить
Привязка представлений включается отдельно для каждого модуля. Чтобы включить привязку представлений в модуле, задайте для параметра сборки viewBinding значение true в файле build.gradle на уровне модуля, как показано в следующем примере:
Яркий
android { ... buildFeatures { viewBinding true } }
Kotlin
android { ... buildFeatures { viewBinding = true } }
Если вы хотите, чтобы файл макета игнорировался при создании классов привязки, добавьте атрибут tools:viewBindingIgnore="true" в корневое представление этого файла макета:
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
Использование
Если привязка представлений включена для модуля, класс привязки генерируется для каждого XML-файла макета, который содержит модуль. Каждый класс привязки содержит ссылки на корневое представление и все представления, у которых есть идентификатор. Название класса привязки генерируется путем преобразования названия XML-файла в стиль PascalCase и добавления слова Binding в конец.
Допустим, у вас есть файл макета result_profile.xml со следующим кодом:
<LinearLayout ... >
<TextView android:id="@+id/name" />
<ImageView android:cropToPadding="true" />
<Button android:id="@+id/button"
android:background="@drawable/rounded_button" />
</LinearLayout>
Сгенерированный класс привязки называется ResultProfileBinding. В этом классе два поля: TextView с названием name и Button с названием button. У элемента ImageView в макете нет идентификатора, поэтому в классе привязки нет ссылки на него.
Каждый класс привязки также включает метод getRoot(), предоставляющий прямую ссылку на корневое представление соответствующего файла макета. В этом примере метод getRoot() в классе ResultProfileBinding возвращает корневое представление LinearLayout.
В следующих разделах показано, как использовать сгенерированные классы привязки в действиях и фрагментах.
Как использовать привязку представлений в действиях
Чтобы настроить экземпляр класса связывания для использования с действием, выполните следующие шаги в методе onCreate() действия:
- Вызовите статический метод
inflate(), включенный в сгенерированный класс привязки. Это создаст экземпляр класса привязки, который будет использоваться действием. - Получите ссылку на корневое представление, вызвав метод
getRoot()или используя синтаксис свойств Kotlin. - Передайте корневое представление в
setContentView(), чтобы сделать его активным на экране.
Эти шаги показаны в следующем примере:
Kotlin
private lateinit var binding: ResultProfileBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ResultProfileBinding.inflate(layoutInflater) val view = binding.root setContentView(view) }
Java
private ResultProfileBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ResultProfileBinding.inflate(getLayoutInflater()); View view = binding.getRoot(); setContentView(view); }
Теперь вы можете использовать экземпляр класса привязки для ссылки на любое из представлений:
Kotlin
binding.name.text = viewModel.name binding.button.setOnClickListener { viewModel.userClicked() }
Java
binding.name.setText(viewModel.getName()); binding.button.setOnClickListener(new View.OnClickListener() { viewModel.userClicked() });
Использование привязки представлений во фрагментах
Чтобы настроить экземпляр класса привязки для использования с фрагментом, выполните следующие действия в методе onCreateView() фрагмента:
- Вызовите статический метод
inflate(), включенный в сгенерированный класс привязки. Это создаст экземпляр класса привязки для использования фрагментом. - Получите ссылку на корневое представление, вызвав метод
getRoot()или используя синтаксис свойств Kotlin. - Верните корневое представление из метода
onCreateView(), чтобы сделать его активным представлением на экране.
Kotlin
private var _binding: ResultProfileBinding? = null // This property is only valid between onCreateView and // onDestroyView. private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = ResultProfileBinding.inflate(inflater, container, false) val view = binding.root return view } override fun onDestroyView() { super.onDestroyView() _binding = null }
Java
private ResultProfileBinding binding; @Override public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = ResultProfileBinding.inflate(inflater, container, false); View view = binding.getRoot(); return view; } @Override public void onDestroyView() { super.onDestroyView(); binding = null; }
Теперь вы можете использовать экземпляр класса привязки для ссылки на любое из представлений:
Kotlin
binding.name.text = viewModel.name binding.button.setOnClickListener { viewModel.userClicked() }
Java
binding.name.setText(viewModel.getName()); binding.button.setOnClickListener(new View.OnClickListener() { viewModel.userClicked() });
Подсказки для разных конфигураций
При объявлении представлений в нескольких конфигурациях иногда имеет смысл использовать разные типы представлений в зависимости от конкретного макета. Ниже приведен пример фрагмента кода:
# in res/layout/example.xml
<TextView android:id="@+id/user_bio" />
# in res/layout-land/example.xml
<EditText android:id="@+id/user_bio" />
В этом случае можно ожидать, что сгенерированный класс будет содержать поле userBio типа TextView, поскольку TextView – это общий базовый класс. Из-за технических ограничений генератор кода привязки представлений не может определить это и вместо этого генерирует поле View. Для этого нужно будет преобразовать поле с помощью binding.userBio as TextView.
Чтобы обойти это ограничение, привязка представлений поддерживает атрибут tools:viewBindingType, позволяющий указать компилятору, какой тип использовать в сгенерированном коде.
В предыдущем примере вы можете использовать этот атрибут, чтобы компилятор сгенерировал поле как TextView:
# in res/layout/example.xml (unchanged)
<TextView android:id="@+id/user_bio" />
# in res/layout-land/example.xml
<EditText android:id="@+id/user_bio" tools:viewBindingType="TextView" />
Рассмотрим другой пример. Предположим, у вас есть два макета: один содержит BottomNavigationView, а другой – NavigationRailView. Оба класса расширяют NavigationBarView, который содержит большую часть деталей реализации. Если в коде не нужно точно знать, какой подкласс присутствует в текущем макете, вы можете использовать tools:viewBindingType, чтобы задать сгенерированный тип NavigationBarView в обоих макетах:
# in res/layout/navigation_example.xml
<BottomNavigationView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />
# in res/layout-w720/navigation_example.xml
<NavigationRailView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />
Привязка представления не может проверить значение этого атрибута при создании кода. Чтобы избежать ошибок компиляции и выполнения, значение должно соответствовать следующим условиям:
- Значение должно быть классом, унаследованным от
android.view.View. Значение должно быть надклассом тега, в котором оно размещено. Например, следующие значения не будут работать:
<TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. --> <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->Итоговый тип должен быть одинаковым во всех конфигурациях.
Отличия от findViewById
У привязки представлений есть важные преимущества по сравнению с использованием findViewById:
- Безопасность нулевых значений. Поскольку привязка представлений создает прямые ссылки на представления, нет риска исключения нулевого указателя из-за недопустимого идентификатора представления.
Кроме того, если представление присутствует только в некоторых конфигурациях макета, поле, содержащее ссылку на него в классе привязки, помечается как
@Nullable. - Типобезопасность. Поля в каждом классе привязки имеют типы, соответствующие представлениям, на которые они ссылаются в XML-файле. Это означает, что нет риска исключения приведения классов.
Эти различия означают, что несовместимость между макетом и кодом приводит к сбою сборки во время компиляции, а не во время выполнения.
Сравнение с привязкой данных
Привязка представлений и привязка данных генерируют классы привязки, которые можно использовать для прямой ссылки на представления. Однако привязка представлений предназначена для более простых сценариев использования и имеет следующие преимущества по сравнению с привязкой данных:
- Более быстрая компиляция. Привязке представлений не требуется обработка аннотаций, поэтому компиляция выполняется быстрее.
- Простота использования. Привязка представлений не требует специально помеченных XML-файлов макета, поэтому ее быстрее внедрить в приложения. После включения привязки представлений в модуле она автоматически применяется ко всем макетам этого модуля.
С другой стороны, привязка представления имеет следующие ограничения по сравнению с привязкой данных:
- Привязка представлений не поддерживает переменные и выражения макета, поэтому ее нельзя использовать для объявления динамического контента пользовательского интерфейса прямо из XML-файлов макета.
- Привязка представлений не поддерживает двустороннюю привязку данных.
Поэтому в некоторых случаях лучше использовать в проекте и привязку представлений, и привязку данных. Вы можете использовать привязку данных в макетах, требующих расширенных функций, и привязку представлений в макетах, которые этого не делают.
Дополнительные ресурсы
Чтобы узнать больше о привязке представлений, ознакомьтесь со следующими дополнительными ресурсами:
Блоги
Видео
Рекомендуем
- Примечание. Текст ссылки показывается, когда JavaScript отключен.
- Как перейти с Kotlin Synthetics на привязку представлений Jetpack
- Макеты и выражения привязки
- Архитектура приложения: уровень интерфейса – Начало работы – Android для разработчиков