- Урок 18. Android Data Binding. Основы
- Делаем Android View Binding удобным c Kotlin
- Стандартный способ работы с View Binding
- Kotlin Delegated Property в бой
- Момент, когда что-то пошло не так.
- From Kotlin synthetics to Android ViewBinding: the definitive guide
- Binding your views like a pro in 2 minutes.
- Setup
- Enable view binding
- Remove android extensions plugin
- Parcelize annotations
- Activities
- Fragments
- ViewHolder
- Includes
- With a view group
- With a
- Conclusion
- Урок 8. Android Data Binding – основы
- Data Binding Library
- С чего начать
- Что нам понадобится
- Подключаем Data Binding в проект
Урок 18. Android Data Binding. Основы
В этом уроке знакомимся с Data Binding.
Полный список уроков курса:
В build.gradle файл модуля в секции android необходимо включить Data Binding:
Правильно произносить байндинг , но биндинг звучит проще — буду использовать его.
Data Binding поможет организовать работу с View так, чтобы нам не пришлось писать кучу методов findViewById, setText, setOnClickListener и т.п. Давайте рассмотрим простой пример.
Есть класс Employee, который содержит в себе данные о работнике
поля: 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.
Это делается следующим образом.
Сначала создаем 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:
Или можно вызывать метод invalidateAll:
Биндинг считает новые данные с ранее полученного объекта Employee.
Поля в Employee в этом примере я сделал public. Но вы можете сделать их private и создать для них public get методы.
Возможно, использование биндинга для пары TextView кажется бессмысленным. Но когда таких TextView десятки, то биндинг может избавить вас от написания кучи кода.
Кроме того, мы рассмотрели совсем простой случай использования биндинга. Но его возможности гораздо шире. Например, можно сделать так, чтобы при передаче в атрибут ImageView ссылки на картинку, биндинг запускал Picasso для загрузки этой картинки и помещал результат в ImageView. Или биндинг может сам отслеживать изменения в объекте с данными (в примере выше — это Employee ) и обновлять экран без каких-либо дополнительных методов.
Эти возможности мы рассмотрим в следующих уроках.
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Делаем Android View Binding удобным c Kotlin
Привет! Меня зовут Кирилл Розов. Я автор Telegram канала Android Broadcast. Очень люблю Kotlin и мне нравится с помощью его возможностей упрощать разработку. С такой задачей я недавно столкнулся, когда на новом Android проекте начали использовать View Binding.
Эта возможность появилась в Android Studio 3.6, но на самом деле она не совсем новая, а облегченный вариант Android Data Binding. Зачем столько усложнений? Проблема была в скорости — множество разработчиков использовали Android Data Binding только для генерации кода со ссылками на View и игнорировали другие возможности библиотеки. Чтобы ускорить генерацию кода, создали View Binding . Однако стандартный способ работы с ней — это дублирование кода от которого хочется избавиться.
Стандартный способ работы с View Binding
Разберем работу View Binding на примере Fragment. У нас есть layout ресурс с именем profile.xml (содержимое его неважно). Если мы хотим использовать ViewBinding, тогда в стандартном варианте это будет выглядеть так:
Проблема здесь несколько:
- Много лишнего кода
- Копи паста: каждый Fragment будет иметь аналогичный кусок кода
- Property viewBinding получается nullable и модифицируемым.
Давайте пробовать избавляться от этого с помощью Cилы Kotlin
Kotlin Delegated Property в бой
С помощью делегирования работы с property в Kotlin можно круто повторно использовать код и упростить некоторые задачи. Например, я применил это в случае с ViewBinding . Для этого я сделал свой делегат, который оборачивает создание ViewBinding и очистку его в нужный момент жизненного цикла:
и конечно же функцию-фабрику, чтобы не видеть как делегат создается:
После небольшого рефакторинга с новыми возможностями я получил следующее:
Вроде задача, которая ставилась, была достигнута. Что же могло пойти не так?
Момент, когда что-то пошло не так.
В какой-то момент возникла необходимость чистить View следующим образом:
Но в итоге я получил состояние, что моя ссылка на ViewBinding внутри делегируемого property уже была почищена. Попытка перенести очистку кода до вызова super.onDestroyView() не принесла успеха и я начал копаться в причинах. Виновником стала реализация вызова методов жизненного цикла у Fragment.viewLifecycleOwner .
Событие ON_DESTROY в Fragment.viewLifecycleOwner происходит до вызова Fragment.onDestroyView() , поэтому FragmentViewBindingProperty очищался раньше, чем я того ожидал. Решением стало отложить вызов операции очистки. Все вызовы жизненного цикла вызываются последовательно и на главном потоке, поэтому весь фикс свелся к откладыванию очистки с помощью Handler :
Полный код можно найти здесь и использовать его на своих проектах.
Источник
From Kotlin synthetics to Android ViewBinding: the definitive guide
Binding your views like a pro in 2 minutes.
Since Kotlin 1.4.20, JetBrains deprecated the kotlin-android-extensions plugin in favor of Android View Binding solution.
If you have been using this plugin, it’s time to move on before this feature is completely removed (or switch to Compose?).
For having completely refactored our Android application to use View Binding, we know that it can be somehow painful and sometimes it looks less simple with this new solution. For example, the binding of your view will have to be done differently if you’re working with an Activity or a Fragment. If your layout uses include there are some tricky ways to handle them too.
That’s why we’ve been implementing some convenient methods to make it simpler.
Setup
If you’re refactoring your whole application code, we advise you to do it module per module to avoid committing too many updates.
Enable view binding
To enable the ViewBinding feature, you just need to enable this build feature on your module build.gradle files:
Remove android extensions plugin
If you’ve been using kotlin-android-extensions before, remove the plugin from the build.gradle file too:
Don’t forget to also remove the Android Extensions experimental flag:
Parcelize annotations
The Parcelize annotations have been moved to another package & the previous one has been deprecated.
So, if you used the Kotlin Parcelize annotation to automatize the implementation of your Parcelable objects, you’ll need to use the new plugin :
Then, replace imports in your code from kotlinx.android.parcel to kotlinx.parcelize.
Activities
To set up an Activity to use your binding class you basically have to:
1- Declare a late init variable for your binding class.
2- In the onCreate method, inflate your layout using the static inflate method from the generated Binding class.
3- Call the Activity setContentView with the root view from your binding class.
We can definitely make it way shorter using some extensions:
Our viewBinding method is a simple delegate that inflates lazily the view of the activity by using the inflater method given as a parameter.
In the Activity we just need to declare the binding as a simple val property and set the content view of the activity.
Fragments
Using View Binding in Fragments is quite less easy as you have to do many things to make it works:
- 1- Declare a var property for your binding class instance.
- In the onCreateView callback, inflate the layout for your binding class & return the root view of it.
- To avoid potential leaks, reset your binding class to null in the onDestroyView callback.
As per the official documentation, it should look like that:
That’s a lot of code to add & you should also pay attention to potential leaks on the binding class. This can also be disturbing as the method is quite different from using it in an Activity. Note that you also need to use the !! operator to hide the nullability of the original field.
There’s a lot of room for improvement here and I found a way better solution to deal with it in 1 line:
Yep, really simple!🚀
Here are some explanations:
- We pass to the Fragment constructor the id of our fragment layout, which will be inflated for us.
- We declare the binding property that will handle the fragment lifecycle work for us.
Have a look at this Gist:
Our viewBindingWithBinder simply instantiate a delegate object that will bind the view of our fragment lazily. As the Fragment already inflate the view from the layout id that we pass to it in its constructor, we just need to bind our binding class from it.
The FragmentAutoClearedValueBinding class is the one that will be responsible to clear the reference to the binding class when the fragment gets destroyed by adding an observer to its lifecycle. In the getValue method, we bind the view to our binding class the first time we access our binding property from our fragment.
ViewHolder
If you’ve been using Kotlin synthetics, you probably have something that looks like this:
You can now remove the usage of LayoutContainer and make some updates in your view holder:
Here we have simply changed our constructor to take the binding class in parameter instead of having a view object.
To instantiate your view holder, you can create a static method in a companion object:
Includes
In your layouts, you probably have views that are included in your layout using the include tag. Then, you must be aware that it can be tricky to deal with it with view binding.
With a view group
If your included view has a root view that is a ViewGroup (LinearLayout, FrameLayout, etc.) then you can set an id to the include tag in your main layout.
The generated LayoutBinding class will have a property mergeLayout of type LayoutMergeBinding that reference the layout_mege layout views.
So in an activity, you can easily reference your TextView as:
With a
If your included view uses a tag in it like in this example:
And your main layout is:
Then, the layout_merge.xml file content will be merged into your main layout. But, the binding class will not expose a property titleLbl (it will only contain your root LinearLayout ) 😭.
So, what can you do to access to your titleLbl ? You’ll need to re-bind your view with another binding class. As each layout files have its own binding class, your layout_merge layout will have a LayoutMergeBinding class generated. That’s the one we will use to retrieve our views.
From an activity, you can add another property for the 2nd binding class:
The mergeBinding property will then allow you to access the titleLbl view.
Conclusion
We hope this article was useful to you if you’re still refactoring your views to use ViewBinding or to give you some hints to refactor how you’re using it.
And you, how did you implement it into your app? Don’t hesitate to share with us your tip&tricks!
If you want to join our Bureau of Technology or any other Back Market department, take a look here, we’re hiring! 🦄
Источник
Урок 8. Android Data Binding – основы
Продолжаем курс по обучению основам разработки мобильных приложений в Android Studio на языке Kotlin. В этом уроке познакомимся с Android Data Binding.
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
На этом этапе мы загрузим и запустим простое приложение-пример. Выполните в консоли команду:
Вы также можете клонировать или скачать репозиторий в виде 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:
Источник