Android view binding vs databinding

Fast lane to Data Binding in Android

As an android developer, we all know that we are always finding something that reduces our code and makes code more cleaner. Apart from that set your data to your UI component is very boilerplate code like setText(), setImageResource(), etc.

There are many ways to avoid these things and access directly your UI component in your java or kotlin file like ButterKnife, Kotlin extensions, etc.
But the kotlin extension is now fully deprecated. So what the next…

Android provides us native support to access your UI component and bind your UI components directly to the Data source and that is called ViewBinding and Data Binding.

So in this article, we will learn some basics about view binding and explore how to add data binding to your project.

1. ViewBinding:

ViewBinding is a feature in an android that allows you to access all of the UI components directly via generated Binding classes. Once you enable the view binding in a build.gradle file, it generates Binding classes which contain all UI components references.

If your layout file name is like game_score.xml then it will generate its class with the name like GameScoreBinding.

ViewBinding in an Activity:

ViewBinding in a Fragment:

NOTE: Here I have used the backing property and assign a binding variable to null in the onDestroyeView() method because Fragments outlive their views. Make sure you clean up any references to the binding class instance in the fragment’s onDestroyView() method.

Advantages of View Binding:

Null safety:

Because View Binding directly creates a reference to views, there is not any risk of a null pointer exception.

Type safety:

The Generated binding class has the same class types fields as present in the XML file, so there are no risks for class cast exceptions.

2. Databinding :

Databinding is a support library provided by android to bind your UI components directly to the data source like ViewModel.

What is the main difference between View Binding and Data Binding?

  • With ViewBinding, the layouts do not need a layout tag.
  • ViewBinding is simply to bind your UI components to your code. While Data Binding is used to Bind your UI components to your Data Source.
  • ViewBinding is faster than Data Binding because there is no usage of an annotation processor to generate Binding classes.
  • ViewBinding does not support two-way binding.

So let’s begin to add data binding in your project step by step…..

How to use Data Binding in your project?

Data binding is a support library so you can use it with devices running Android 4.0 (API level 14) or higher.

Step 1:

Enable data binding in your module-level build.gradle file.

Step 2:

Create your Activity, Fragment like below.

To Generate the Data binding class for this UI.

Now Bind your ViewModel with CharacterFragment.

Here the item_charcter.xml for the Recyclerview item.

To Bind your data to this UI.

Add your name and type which you want to bind to this UI.

@<> The expression language allows you to write expressions that handle events dispatched by the views.

With Expression language, you can use the following operators and keywords to manage your UI in a declarative format directly in the XML file.

Mathematical + — / * %
String concatenation +
Logical && ||
Binary & | ^
Unary + — !

Shift >> >>> = Ternary operator to set the vector drawable based on character status.

Step 3:

Now time to bind your data to an XML file.

Here one magic thing I have used to load the image using a binding adapter.

Binding Adapter :

Binding Adapters are used to have custom setters to some property of your views. The most common use case I can think of is setting an image to an ImageView, where loading of the image is mostly done off the UI thread.

Источник

Android ViewBinding vs DataBinding

Sep 5 · 4 min read

Android ViewBinding, Yes or No?

ViewBinding is a great tool that in most cases, replaces findViewById , so you can finialy say goodby to null point function from wrong ID casting. But what is the difference between V iewBinding and DataBinding and what is its pros and cons?

V iewBinding vs DataBinding

The one and only function of View Binding is to bind the views in the code, while Data Binding offers some more options like Binding Expressions, which allows us to write expressions the connect variables to the views in the layout.

Basically ViewBinding only binding views to code, while DataBinding bind data from code to views.

The r e are three important differences

  1. With ViewBinding, the layouts do not need a layout tag
  2. You can’t use ViewBinding to bind layouts with data in xml (No binding expressions, no BindingAdapters nor two-way binding with ViewBinding)
  3. The main advantages of viewbinding are speed and efficiency. It has a shorter build time because it avoids the overhead and performance issues associated with DataBinding due to annotation processors affecting DataBinding’s build time.
Читайте также:  Где найти айпи своего андроида

There is nothing ViewBinding can do that DataBinding cannot but it costs longer build times. Remember you don’t need to use both, if you are using DataBinding, there is no need adding ViewBinding.

View binding is a feature that allows you to more easily write code that interacts with views. It generates a binding class for each XML layout file present in that module. An instance of a binding class contains direct references to all views that have an ID in the corresponding layout — Google

So why we shouldn’t use DataBinding frequently when it sounds much more fancy?!

As much as it sounds fancy, it is a pretty heavy loaded library which might cause a longer compile time. So if you are not going to use DataBinding only functionalities then might be better to consider ViewBinding as it does have some advantages in terms of build time and apk size.

In short you can use ViewBinding to replace findviewbyid() effectively. If your project is however more complex and you need to add features like binding data to views, binding adapters e.t.c, use DataBinding.

Biggest advantage of ViewBinding is Speed and Efficiency

So how we should use ViewBinding?

There is a couple of things you should do and I try to make it organized and listed: (Based on Android Developers docs from this link and my personal experiences)

Step 1: Adding ViewBinding to your project

First you need to use Android Studio 3.6 canary11+ (I’m currently using Android Studio 4.1.2 and it is doing the job well for me)
You can find it from here

Then You need to upgrade your Gradle wrapper to Gradle “5.6.4” and Gradle build tool to “3.6.0-rc01”, higher versions also work so don’t be afraid to be updated
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

To enable view binding in a module, add the viewBinding element to its build.gradle file, as shown in the following example:

Step 2: Using ViewBinding in your project

If view binding is enabled for a module, a binding class is generated for each XML layout file that the module contains. Each binding class contains references to the root view and all views that have an ID. The name of the binding class is generated by converting the name of the XML file to camel case and adding the word “Binding” to the end.
For example, given a layout file called result_profile.xml :

The generated binding class is called ResultProfileBinding . This class has two fields: a TextView called name and a Button called button . The ImageView in the layout has no ID, so there is no reference to it in the binding class.

Every binding class also includes a getRoot() method, providing a direct reference for the root view of the corresponding layout file. In this example, the getRoot() method in the ResultProfileBinding class returns the LinearLayout root view.

If you want a layout file to be ignored while generating binding classes, add the tools:viewBindingIgnore=»true» attribute to the root view of that layout file:

To set up an instance of the binding class for use with an activity, fragment or card view adapter perform the following steps:

  • in the activity’s onCreate() method:
  • in the fragments’s onCreateView() method:
  • in the card view adapter’s onCreateViewHolder() method:

that’s it you are free from the findViewById from now on.

If you find this article useful please don’t hesitate to share it and give applause. If you have questions or would like to give me some feedback, please comment below or follow my social media ( Twitter, Linkedin).
For more information check my answer and its comments in the link below

Источник

Долгожданный View Binding в Android

Пару дней назад Google выпустил Android Studio 3.6 Canary 11, главным нововведением в которой стал View Binding, о котором было рассказано еще в мае на Google I/O 2019.

View Binding — это инструмент, который позволяет проще писать код для взаимодейтсвия с view. При включении View Binding в определенном модуле он генерирует binding классы для каждого файла разметки (layout) в модуле. Объект сгенерированного binding класса содержит ссылки на все view из файла разметки, для которых указан android:id .

Как включить

Чтобы включить View Binding в модуле надо добавить элемент в файл build.gradle :

Также можно указать, что для определенного файла разметки генерировать binding класс не надо. Для этого надо указать аттрибут tools:viewBindingIgnore=»true» в корневой view в нужном файле разметки.

Как использовать

Каждый сгенерированный binding класс содержит ссылку на корневой view разметки ( root ) и ссылки на все view, которые имеют id. Имя генерируемого класса формируется как «название файла разметки», переведенное в camel case + «Binding».

Например, для файла разметки result_profile.xml :

Будет сгенерирован класс ResultProfileBinding , содержащий 2 поля: TextView name и Button button . Для ImageView ничего сгенерировано не будет, как как оно не имеет id . Также в классе ResultProfileBinding будет метод getRoot() , возвращающий корневой LinearLayout .

Чтобы создать объект класса ResultProfileBinding , надо вызвать статический метод inflate() . После этого можно использовать корневой view как content view в Activity :

Позже binding можно использовать для получения view:

Отличия от других подходов

Главные преимущества View Binding — это Null safety и Type safety.

При этом, если какая-то view имеется в одной конфигурации разметки, но отсутствует в другой ( layout-land , например), то для нее в binding классе будет сгенерировано @Nullable поле.

Также, если в разных конфигурациях разметки имеются view с одинаковыми id, но разными типами, то для них будет сгенерировано поле с типом android.view.View .
(По крайней мере, в версии 3.6 Canary 11)

А вообще, было бы удобно, если бы сгенерированное поле имело наиболее возможный специфичный тип. Например, чтобы для Button в одной конфигурации и TextView в другой генерировалось поле с типом TextView ( public class Button extends TextView ).

Читайте также:  Android удаляем аккаунт гугл

При использовании View Binding все несоответствия между разметкой и кодом будут выявляться на этапе компиляции, что позволит избежать ненужных ошибок во время работы приложения.

Использование в RecyclerView.ViewHolder

Ничего не мешает использовать View Binding при создании view для RecyclerView.ViewHolder :

Однако, для создания такого ViewHolder придется написать немного бойлерплейта:

Было бы удобнее, если при работе с RecyclerView.ViewHolder метод inflate(. ) не будет иметь параметр layoutInflater , а будет сам получать его из передаваемого parent .

Тут нужно ещё упомянуть, что при использовании View Binding поиск view через findViewById() производится только один раз при вызове метода inflate() . Это дает преимущество над kotlin-android-extensions , в котором кеширование view по умолчанию работало только в Activity и Fragment , а для RecyclerView.ViewHolder требовалась дополнительная настройка.

В целом, View Binding это очень удобная вещь, которую легко начать использовать в существующих проектах. Создатель Butter Knife уже рекомендует переключаться на View Binding.

Немного жаль, что такой инструмент не появился несколько лет назад.

Источник

Android Architecture Components в связке с Data Binding

Не так давно для андроид-разработчиков Google представил новую библиотеку — Android Architecture Components. Она помогает реализовать в приложении архитектуру на основе паттернов MVx (MVP, MVVM etc.). Кроме того, уже давно выпущена другая библиотека от Google — Data Binding Library. Она позволяет прямо в разметке связывать отображение UI-контролов со значениями, содержащимися в объектах. Это важная особенность паттерна MVVM — связывать слой View со слоем ViewModel.

Обе библиотеки направлены на построение архитектуры Android-приложений в MVVM стиле.
Я расскажу, как можно использовать их вместе для создания проекта с архитектурой на основе MVVM.

Немного об MVVM

Паттерн MVVM предполагает разделение архитектуры приложения на 3 слоя:

  • Model — слой данных. Содержит всю бизнес-логику приложения, доступ к файловой системе, базе данных, ресурсам системы и другим внешним сервисам;
  • View — слой отображения. Все, что видит пользователь и с чем может взаимодействовать. Этот слой отображает то, что представлено в слое ViewModel. Также он отправляет команды (например, действия пользователя) на выполнение в слой ViewModel;
  • ViewModel — слой представления. Связан со слоем View байндингами. Содержит данные, которые отображены на слое View. Связан со слоем Model и получает оттуда данные для отображения. Также обрабатывает команды, поступающие из слоя View, изменяя тем самым слой Model.


Основной интерес в статье будет прикован к байндингам. Это связи отображения конкретных параметров View (например, “text” у TextView) с конкретными полями представления ViewModel (например, поле “имя пользователя”). Задаются они в разметке View (в layout), а не в коде. ViewModel, в свою очередь, должна так представлять данные, чтобы их было легко связать байндингами с View.

Зачем нам это все надо?

Сам по себе паттерн MVVM, как и MVP, и MVC, позволяет разделить код на независимые слои. Основное отличие MVVM — в байндингах. То есть, в возможности прямо в разметке связать отображение того, что видно пользователю — слой View, с состоянием приложения — слоем Model. В общем, польза MVVM в том, чтобы не писать лишний код для связывания представления с отображением — за вас это делают байндинги.

Google двигается в сторону поддержки архитектуры на основе паттерна MVVM. Библиотеки Android Architecture Components (далее, AAC) и Data Binding — прямое тому подтверждение. В будущем, скорее всего, этот паттерн будет использоваться на большинстве проектах под Android.

На данный момент проблема в том, что ни AAC, ни Data Binding не предоставляет возможности реализовать MVVM паттерн в полной мере. AAC реализует слой ViewModel, но байндинги надо настраивать вручную в коде. Data Binding, в свою очередь, предоставляет возможность написать байндинги в разметке и привязать их к коду, но слой ViewModel надо реализовывать вручную, чтобы прокидывать обновление состояния приложения через байндинги к View.

В итоге, вроде бы, все уже готово, но разделено на две библиотеки, и чтобы это было действительно похоже на MVVM, нужно просто взять и объединить их.

В общем, что надо для этого сделать:

  • реализовать слой View на байндингах;
  • реализовать слой ViewModel на основе классов LiveData и ViewModel из AAC;
  • связать эти два слоя минимальным количеством кода;
  • оформить это так, чтобы это можно было переиспользовать в проектах.

Сделать это попробуем на примере простого экрана профиля пользователя.

Описание примера

На экране будет три элемента:

  • кнопка войти/выйти. Текст зависит от того, авторизован пользователь или нет;
  • поле ввода логина. Показывается, когда пользователь не авторизован;
  • лэйбл с логином. Показывает логин авторизованного пользователя.

Логин будет храниться в SharedPreferences. Пользователь считается авторизованным, если в SharedPreferences записан какой-нибудь логин.

Для простоты не будут использоваться сторонние фреймворки, запросы к сети, а также отображение ошибок.

Слой View

Начну я со слоя View, чтобы было понятно, что будет видно пользователю на экране. Сразу же размечу нужные мне байндинги без привязки к конкретной ViewModel. Как это все будет работать — станет понятно позже.

Класс LiveData

Перед реализацией слоя Model надо разобраться с классом LiveData из AAC. Он нам понадобится для нотификации слоя ViewModel об изменениях слоя Model.

LiveData — это класс, объекты которого поставляют данные и их обновления подписчикам. Он представляет собой реализацию паттерна Observer. На LiveData можно подписаться, а сама LiveData реализует внутри то, как она будет вычислять и обновлять данные для подписчиков.

Особенность LiveData в том, что она может быть привязана к объекту жизненного цикла и активироваться, только когда такой объект в состоянии started. Это удобно для обновления слоя View: пока активити или фрагмент в состоянии started, это значит, что у них инициализирован весь UI и им нужны актуальные данные. LiveData реагирует на это и активизируется — рассчитывает актуальное значение и уведомляет подписчиков об обновлении данных.

Слой Model

От слоя Model нам нужна следующая функциональность: методы login(String login), logout() и возможность отслеживать текущий логин авторизованного пользователя на основе LiveData.

Читайте также:  Блестящие живые обои для андроида

Добавим класс ProfileRepository, который будет отвечать за логику авторизации пользователя:

Этот объект разместим в Application, чтобы было проще получить к нему доступ, имея Context:

Класс ViewModel

Перед реализацией слоя ViewModel надо разобраться с основным классом из AAC, использующимся для этого.

ViewModel — это класс, представляющий объекты слоя ViewModel. Объект такого типа может быть создан из любой точки приложения. В этом классе всегда должен быть либо дефолтный конструктор (класс ViewModel), либо конструктор с параметром типа Application (класс AndroidViewModel).

Чтобы запросить ViewModel по типу, нужно вызвать:

ViewModel хранятся отдельно для каждой активити и для каждого фрагмента. При первом запросе они создаются и помещаются для хранения в активити или фрагменте. При повторном запросе — возвращается уже созданная ViewModel. Уникальность конкретной ViewModel — это ее тип или строковый ключ + где она хранится.

Создаются ViewModel и AndroidViewModel по умолчанию через рефлексию — вызывается соответствующий конструктор. Так что, при добавлении своих конструкторов, в методе ViewModelProviders.of(. ) нужно явно указывать фабрику создания таких объектов.

Слой ViewModel

От ProfileViewModel нам надо следующее:

  • метод loginOrLogout, который будет представлять команду логина или логаута пользователя, в зависимости от того, авторизован ли пользователь;
  • изменяемое значение isUserLoggedIn, которое будет представлять состояние — авторизован ли пользователь;
  • изменяемое значение loggedInUser, которое будет представлять логин текущего авторизованного пользователя;
  • изменяемое значение inputLogin, которое будет представлять то, что пользователь ввел на экране в поле логина.

Создадим ProfileViewModel и свяжем ее с ProfileRepository:

Теперь при вызове метода loginOrLogout в ProfileRepository будет обновляться LoginLiveData и эти обновления можно будет отображать на слое View, подписавшись на LiveData из ProfileViewModel.

Но LiveData и ViewModel пока что не адаптированы под байндинг, так что использовать этот код еще нельзя.

Адаптация ViewModel под Data Binding

С доступом к ViewModel из разметки проблем особых нет. Объявляем ее в разметке:

И устанавливаем в активити или фрагменте:

Адаптация LiveData под Data Binding

Адаптировать LiveData я решил на основе класса ObservableField. Он позволяет привязать изменяющееся значение произвольного типа к конкретному свойству view.

В моем примере надо будет прибайндить visibility у view к тому, авторизован пользователь или нет. А также свойство text к логину пользователя.

У ObservableField есть два метода — addOnPropertyChangedCallback и removeOnPropertyChangedCallback. Эти методы вызываются, когда добавляется и удаляется байндинг из view.
По сути, эти методы — те моменты, когда нужно подписываться и отписываться от LiveData:

Для подписки на LiveData я использовал метод observeForever. Он не передает объект жизненного цикла и активирует LiveData независимо от того, в каком состоянии находятся активити или фрагмент, на котором находятся view.

В принципе, из объекта OnPropertyChangedCallback можно достать view, из view — context, context привести к LifecycleActivity и привязать LiveData к этой активити. Тогда можно будет использовать метод observe(lifecycleObject, observer). Тогда LiveData будет активироваться только когда активити, на которой находится view, в состоянии started.

Выглядеть этот хак будет примерно так:

Теперь изменим ProfileViewModel так, чтобы к ней можно было легко прибайндиться:

Важно! В процессе тестирования обнаружился один неприятный недостаток в библиотеке Data Binding — прибайнденные view не вызывают метод removeOnPropertyChangedCallback даже когда активити умирает. Это приводит к тому, что слой Model держит ссылки на объекты слоя View через слой ViewModel. В общем, утечка памяти из объектов LiveDataField.

Чтобы этого избежать, можно использовать еще один хак и вручную обнулить все байндинги на onDestroy активити:

Кроме того, внимательные читатели могли заметить в разметке класс SafeEditText. В общем, он понадобился, из-за бага в Data Binding Library. Суть в том, что она добавляет в листенер вводимого текста через addTextChangedListener даже если этот листенер null.
Так как на этапе onDestroy я обнуляю модель, то сперва в EditText добавляется null-листенер, а потом обновляется текст, который стал тоже null. В итоге на onDestroy происходил NPE краш при попытке оповестить null-листенер о том, что текст стал null.

В общем, при использовании Data Binding будьте готовы к таким багам — их там довольно много.

Не идеально, но получилось

В общем, с некоторыми трудностями, хаками и некоторыми разочарованиями, но связать AAC и Data Binding получилось. Скорее всего, в скором времени (года 2?) Google добавит какие-нибудь фичи, чтобы связать их — тот же аналог моей LiveDataField. Пока что AAC в альфе, так что там многое еще может измениться.

Основные проблемы на текущий момент, на мой взгляд, связаны с библиотекой Data Binding — она не подстроена под работу с ViewModel и в ней есть неприятные баги. Это наглядно видно из хаков, которые пришлось использовать в статье.

Во-первых, при байндинге сложно получить активити или фрагмент, чтобы получить LifecycleObject, необходимый для LiveData. Эту проблему можно решить: либо достаем это через рефлексию, либо просто делаем observeForever, который будет держать подписку на LiveData, пока мы вручную не обнулим байндинги на onDestroy.

Во-вторых, Data Binding предполагает, что ObservableField и прочие Observable объекты живут тем же жизненным циклом, что и view. По факты эти объекты — это часть слоя ViewModel, у которой другой жизненный цикл. Например, в AAC этот слой переживает перевороты активити, а Data Binding, не обновляет байндинги после переворота активити — для нее все view умерли, а значит, и все Observable объекты тоже умерли и обновлять ничего нет смысла. Эту проблему можно решить обнулением байндингов вручную на onDestroy. Но это требует лишнего кода и необходимости следить, что все байндинги обнулены.

В-третьих, возникает проблема с объектами слоя View без явного жизненного цикла, например, ViewHolder адаптера для RecyclerView. У них нет четкого вызова onDestroy, так как они переиспользуются. В какой момент обнулять байндинги во ViewHolder — сложно сказать однозначно.

Не сказал бы, что на текущий момент связка этих библиотек выглядит хорошо, хотя использовать ее можно. Стоит ли использовать такой подход с учетом недостатков, описанных выше — решать вам.

Пример из статьи можно посмотреть на гитхабе Touch Instinct.

Источник

Оцените статью