Эта кодовая лаборатория является частью курса Android Kotlin Fundamentals. Вы получите максимальную отдачу от этого курса, если будете последовательно работать с лабораториями кода. Все кодовые лаборатории курса перечислены на целевой странице кодовых лабораторий Android Kotlin Fundamentals .
Введение
В предыдущих лабораторных работах этого курса вы использовали функцию findViewById()
для получения ссылок на представления. Когда ваше приложение имеет сложную иерархию представлений, findViewById()
затрат и замедляет работу приложения, поскольку Android проходит иерархию представлений, начиная с корня, пока не найдет нужное представление. К счастью, есть лучший способ.
Чтобы установить данные в представлениях, вы использовали строковые ресурсы и установили данные из действия. Было бы более эффективно, если бы представление знало о данных. И, к счастью, это снова возможно.
В этой лабораторной работе вы узнаете, как использовать привязку данных, чтобы устранить необходимость в findViewById()
. Вы также узнаете, как использовать привязку данных для доступа к данным непосредственно из представления.
Что вы уже должны знать
Вы должны быть знакомы с:
- Что такое активность и как настроить активность с макетом в
onCreate()
. - Создание текстового представления и настройка текста, отображаемого в текстовом представлении.
- Использование
findViewById()
для получения ссылки на представление. - Создание и редактирование базового макета XML для представления.
Что вы узнаете
- Как использовать библиотеку привязки данных для устранения неэффективных вызовов
findViewById()
. - Как получить доступ к данным приложения напрямую из XML.
Что ты будешь делать
- Измените приложение, чтобы использовать привязку данных вместо
findViewById()
и получать доступ к данным непосредственно из XML-файлов макета.
В этой лаборатории кода вы начинаете с приложения AboutMe и изменяете приложение для использования привязки данных. Приложение будет выглядеть точно так же, когда вы закончите!
Вот что делает приложение AboutMe:
- Когда пользователь открывает приложение, оно показывает имя, поле для ввода псевдонима, кнопку « Готово », звездочку и прокручиваемый текст.
- Пользователь может ввести псевдоним и нажать кнопку « Готово ». Редактируемое поле и кнопка заменяются текстовым представлением, которое показывает введенный псевдоним.
Вы можете использовать код, созданный в предыдущей лаборатории кода, или загрузить код AboutMeDataBinding-Starter с GitHub.
Код, который вы написали в предыдущих лабораторных работах, использует функцию findViewById()
для получения ссылок на представления.
Каждый раз, когда вы используете findViewById()
для поиска представления после его создания или повторного создания, система Android просматривает иерархию представлений во время выполнения, чтобы найти его. Если у вашего приложения всего несколько просмотров, это не проблема. Однако рабочие приложения могут иметь десятки представлений в макете, и даже при самом лучшем дизайне будут вложенные представления.
Подумайте о линейном макете, который содержит представление прокрутки, содержащее текстовое представление. Для большой или глубокой иерархии представлений поиск представления может занять достаточно времени, что может заметно замедлить работу приложения для пользователя. Кэширование представлений в переменных может помочь, но вам все равно придется инициализировать переменную для каждого представления в каждом пространстве имен. С большим количеством просмотров и несколькими действиями это тоже складывается.
Одним из решений является создание объекта, содержащего ссылку на каждое представление. Этот объект, называемый объектом Binding
, может использоваться всем вашим приложением. Этот метод называется привязкой данных . После создания объекта привязки для вашего приложения вы можете получить доступ к представлениям и другим данным через объект привязки без необходимости просматривать иерархию представлений или искать данные.
Привязка данных имеет следующие преимущества:
- Код короче, его легче читать и легче поддерживать, чем код, использующий
findByView()
. - Данные и представления четко разделены. Это преимущество привязки данных становится все более важным позже в этом курсе.
- Система Android проходит иерархию представлений только один раз, чтобы получить каждое представление, и это происходит во время запуска приложения, а не во время выполнения, когда пользователь взаимодействует с приложением.
- Вы получаете безопасность типов для доступа к представлениям. ( Безопасность типов означает, что компилятор проверяет типы во время компиляции и выдает ошибку, если вы пытаетесь присвоить переменной неправильный тип.)
В этой задаче вы настраиваете привязку данных и используете привязку данных для замены вызовов findViewById()
вызовами объекта привязки.
Шаг 1. Включите привязку данных
Чтобы использовать привязку данных, вам необходимо включить привязку данных в файле Gradle, так как она не включена по умолчанию. Это связано с тем, что привязка данных увеличивает время компиляции и может повлиять на время запуска приложения.
- Если у вас нет приложения AboutMe из предыдущей кодовой лаборатории, получите код AboutMeDataBinding-Starter на GitHub. Откройте его в Android Studio.
- Откройте
build.gradle (Module: app)
. - Внутри раздела
android
перед закрывающей скобкой добавьте разделdataBinding
и установите для параметраenabled
значениеtrue
.
dataBinding {
enabled = true
}
- При появлении запроса синхронизируйте проект. Если вас не попросят, выберите «Файл» > «Синхронизировать проект с файлами Gradle» .
- Вы можете запустить приложение, но вы не увидите никаких изменений.
Шаг 2. Измените файл макета, чтобы его можно было использовать с привязкой данных
Для работы с привязкой данных вам необходимо обернуть XML-макет тегом <layout>
. Это связано с тем, что корневой класс больше не является группой представлений, а представляет собой макет, содержащий группы представлений и представления. Затем объект привязки может знать о макете и представлениях в нем.
- Откройте файл
activity_main.xml
. - Переключитесь на вкладку « Текст ».
- Добавьте
<layout></layout>
в качестве самого внешнего тега вокруг<LinearLayout>
.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- Выберите « Код» > «Переформатировать код» , чтобы исправить отступ кода.
Объявления пространств имен для макета должны находиться в самом внешнем теге.
- Вырежьте объявления пространств имен из
<LinearLayout>
и вставьте их в<layout>
. Ваш открывающий<layout>
должен выглядеть так, как показано ниже, а<LinearLayout>
должен содержать только свойства представления.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- Создайте и запустите приложение, чтобы убедиться, что вы сделали это правильно.
Шаг 3: Создайте объект привязки в основном действии
Добавьте ссылку на объект привязки в основное действие, чтобы вы могли использовать его для доступа к представлениям:
- Откройте файл
MainActivity.kt
. - Перед
onCreate()
на верхнем уровне создайте переменную для объекта привязки. Эта переменная обычно называетсяbinding
.
Типbinding
, классActivityMainBinding
, создается компилятором специально для этого основного действия. Имя происходит от имени файла макета, то естьactivity_main + Binding
.
private lateinit var binding: ActivityMainBinding
- По запросу Android Studio импортируйте
ActivityMainBinding
. Если вас не попросят, нажмитеActivityMainBinding
и нажмитеAlt+Enter
(Option+Enter
на Mac), чтобы импортировать этот отсутствующий класс. (Дополнительные сочетания клавиш см. в разделе Сочетания клавиш .)
Операторimport
должен выглядеть примерно так, как показано ниже.
import com.example.android.aboutme.databinding.ActivityMainBinding
Затем вы заменяете текущую setContentView()
инструкцией, которая делает следующее:
- Создает объект привязки.
- Использует
setContentView()
из классаDataBindingUtil
, чтобы связать макетactivity_main
сMainActivity
. ЭтаsetContentView()
также выполняет некоторые настройки привязки данных для представлений.
- В
onCreate()
заменитеsetContentView()
следующей строкой кода.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Импортируйте
DataBindingUtil
.
import androidx.databinding.DataBindingUtil
Шаг 4: Используйте объект привязки для замены всех вызовов findViewById()
Теперь вы можете заменить все вызовы findViewById()
ссылками на представления, находящиеся в объекте привязки. Когда объект привязки создан, компилятор генерирует имена представлений в объекте привязки из идентификаторов представлений в макете, преобразовывая их в верблюжий регистр. Так, например, done_button
становится doneButton
в объекте привязки, nickname_edit
становится nicknameEdit
, а nickname_text
становится nicknameText
.
- В
onCreate()
замените код, использующийfindViewById()
для поискаdone_button
, кодом, который ссылается на кнопку в объекте привязки.
Замените этот код:findViewById<Button>(R.id.
done_button
)
с помощью:binding.doneButton
Ваш готовый код для установки прослушивателя кликов вonCreate()
должен выглядеть так.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- Сделайте то же самое для всех вызовов
findViewById()
в функцииaddNickname()
.
Замените все вхожденияfindViewById<
View
>(R.id.
id_view
)
binding.
idView
. Сделайте это следующим образом:
- Удалите определения для переменных
editText
иnicknameTextView
вместе с их вызовамиfindViewById()
. Это даст вам ошибки. - Исправьте ошибки, получив представления
nicknameText
,nicknameEdit
иdoneButton
из объектаbinding
вместо (удаленных) переменных. - Замените
view.visibility
наbinding.doneButton.visibility
. Использованиеbinding.doneButton
вместо переданногоview
делает код более согласованным.
В результате получается следующий код:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
- В функционале изменений нет. При желании теперь вы можете удалить параметр
view
и обновить все виды использованияview
, чтобы использоватьbinding.doneButton
внутри этой функции.
- Для
nicknameText
требуетсяString
, а дляnicknameEdit.text
требуетсяEditable
. При использовании привязки данных необходимо явно преобразоватьEditable
вString
.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- Вы можете удалить выделенный серым цветом импорт.
- Котлинизируйте функцию с помощью
apply{}
.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- Создайте и запустите свое приложение... и оно должно выглядеть и работать точно так же, как и раньше.
Вы можете воспользоваться преимуществами привязки данных, чтобы сделать класс данных непосредственно доступным для представления. Этот метод упрощает код и чрезвычайно полезен для обработки более сложных случаев.
В этом примере вместо установки имени и псевдонима с помощью строковых ресурсов вы создаете класс данных для имени и псевдонима. Вы делаете класс данных доступным для представления с помощью привязки данных.
Шаг 1. Создайте класс данных MyName.
- В Android Studio в каталоге
java
откройте файлMyName.kt
. Если у вас нет этого файла, создайте новый файл Kotlin и назовите егоMyName.kt
. - Определите класс данных для имени и псевдонима. Используйте пустые строки в качестве значений по умолчанию.
data class MyName(var name: String = "", var nickname: String = "")
Шаг 2. Добавьте данные в макет
В файле activity_main.xml
имя в настоящее время задается в TextView
из строкового ресурса. Вам нужно заменить ссылку на имя ссылкой на данные в классе данных.
- Откройте файл
activity_main.xml
на вкладке « Текст ». - В верхней части макета между тегами
<layout>
и<LinearLayout>
вставьте<data></data>
. Здесь вы будете соединять представление с данными.
<data>
</data>
Внутри тегов данных вы можете объявить именованные переменные, содержащие ссылку на класс.
- Внутри
<data>
добавьте тег<variable>
. - Добавьте параметр
name
, чтобы дать переменной имя"myName"
. Добавьте параметрtype
и задайте для типа полное имя класса данныхMyName
(имя пакета + имя переменной).
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
Теперь вместо использования строкового ресурса для имени вы можете ссылаться на переменную myName
.
- Замените
android:text="@string/name"
приведенным ниже кодом.
@={}
— это директива для получения данных, на которые ссылаются фигурные скобки.
myName
ссылается на ранее определенную вами переменную myName
, которая указывает на класс данных myName
и извлекает свойство name
из класса.
android:text="@={myName.name}"
Шаг 3: Создайте данные
Теперь у вас есть ссылка на данные в файле макета. Затем вы создаете фактические данные.
- Откройте файл
MainActivity.kt
. - Над
onCreate()
создайте приватную переменную, также называемуюmyName
по соглашению. Назначьте переменной экземпляр класса данныхMyName
, передав имя.
private val myName: MyName = MyName("Aleks Haecky")
- В
onCreate()
установите значение переменнойmyName
в файле макета на значение только что объявленной переменнойmyName
. Вы не можете получить доступ к переменной в XML напрямую. Вам нужно получить к нему доступ через объект привязки.
binding.myName = myName
- Это может показать ошибку, потому что вам нужно обновить объект привязки после внесения изменений. Создайте свое приложение, и ошибка должна исчезнуть.
Шаг 4: Используйте класс данных для псевдонима в TextView
Последний шаг — также использовать класс данных для псевдонима в TextView
.
- Откройте файл
activity_main.xml
. - В текстовом представлении
nickname_text
добавьте свойствоtext
. Ссылка наnickname
в классе данных, как показано ниже.
android:text="@={myName.nickname}"
- В
ActivityMain
замените
nicknameText.text = nicknameEdit.text.toString()
с кодом для установки псевдонима в переменнойmyName
.
myName?.nickname = nicknameEdit.text.toString()
После того, как псевдоним установлен, вы хотите, чтобы ваш код обновлял пользовательский интерфейс с новыми данными. Для этого необходимо аннулировать все выражения привязки, чтобы они воссоздавались с правильными данными.
- Добавьте
invalidateAll()
после установки псевдонима, чтобы пользовательский интерфейс обновлялся со значением в обновленном объекте привязки.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- Создайте и запустите свое приложение, и оно должно работать точно так же, как и раньше.
Проект Android Studio: AboutMeDataBinding
Шаги по использованию привязки данных для замены вызовов findViewById()
:
- Включите привязку данных в разделе android файла
build.gradle
:
dataBinding { enabled = true }
- Используйте
<layout>
в качестве корневого представления в макете XML. - Определите переменную привязки:
private lateinit var binding: ActivityMainBinding
- Создайте объект привязки в
MainActivity
, заменивsetContentView
:
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Замените вызовы
findViewById()
ссылками на представление в объекте привязки. Например:
findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
binding.doneButton
(В этом примере имя представления генерируется в верблюжьем регистре изid
представления в XML.)
Шаги для привязки представлений к данным:
- Создайте класс данных для ваших данных.
- Добавьте блок
<data>
внутрь<layout>
. - Определите
<variable>
с именем и типом, который является классом данных.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- В
MainActivity
создайте переменную с экземпляром класса данных. Например:
private val myName: MyName = MyName("Aleks Haecky")
- В объекте привязки установите переменную в только что созданную переменную:
binding.myName = myName
- В XML задайте для содержимого представления переменную, которую вы определили в блоке
<data>
. Используйте запись через точку для доступа к данным внутри класса данных.
android:text="@={myName.name}"
Удасити курс:
Документация для разработчиков Android:
В этом разделе перечислены возможные домашние задания для студентов, которые работают с этой кодовой лабораторией в рамках курса, проводимого инструктором. Инструктор должен сделать следующее:
- При необходимости задайте домашнее задание.
- Объясните учащимся, как сдавать домашние задания.
- Оценивайте домашние задания.
Преподаватели могут использовать эти предложения так мало или так часто, как они хотят, и должны свободно давать любые другие домашние задания, которые они считают подходящими.
Если вы работаете с этой кодовой лабораторией самостоятельно, не стесняйтесь использовать эти домашние задания, чтобы проверить свои знания.
Ответьте на эти вопросы
Вопрос 1
Почему вы хотите свести к минимуму явные и неявные вызовы findViewById()
?
- Каждый раз, когда вызывается
findViewById()
, он проходит через иерархию представлений. -
findViewById()
работает в основном потоке или потоке пользовательского интерфейса. - Эти вызовы могут замедлить работу пользовательского интерфейса.
- Ваше приложение с меньшей вероятностью выйдет из строя.
вопрос 2
Как бы вы описали привязку данных?
Например, вот что можно сказать о привязке данных:
- Основная идея привязки данных заключается в создании объекта, который соединяет/сопоставляет/связывает две части удаленной информации вместе во время компиляции, чтобы вам не приходилось искать данные во время выполнения.
- Объект, который отображает эти привязки для вас, называется объектом привязки .
- Объект привязки создается компилятором.
Вопрос 3
Что из следующего НЕ является преимуществом привязки данных?
- Код короче, его легче читать и легче поддерживать.
- Данные и представления четко разделены.
- Система Android проходит иерархию представлений только один раз, чтобы получить каждое представление.
- Вызов
findViewById()
генерирует ошибку компилятора. - Введите безопасность для доступа к представлениям.
Вопрос 4
Какова функция <layout>
?
- Вы оборачиваете его вокруг своего корневого представления в макете.
- Привязки создаются для всех представлений в макете.
- Он обозначает представление верхнего уровня в макете XML, использующем привязку данных.
- Вы можете использовать
<data>
внутри<layout>
для привязки переменной к классу данных.
Вопрос 5
Как правильно ссылаться на связанные данные в макете XML?
-
android:text="@={myDataClass.property}"
-
android:text="@={myDataClass}"
-
android:text="@={myDataClass.property.toString()}"
-
android:text="@={myDataClass.bound_data.property}"
Начать следующий урок:
Ссылки на другие лаборатории кода в этом курсе см. на целевой странице лаборатории кода Android Kotlin Fundamentals .