Development, Exaud Insights
Android Data Binding – Part I
The Data Binding Library is the process that establishes a connection between an application UI and a business logic. With Data Binding Library we can easily setup layouts without needing to write a lot of boilerplate code. It allowed us, as well, to use a 2-way Data Binding, which will ensure the data is updated each time the UI changes.
Today, I am going to explain to you how to use Data Binding, using as an example an app to create notes. Check the next steps!
Configuration
In order to start using Data Binding in an Android project we simply need to enable it by changing build.gradle with the following setting:
android { ... dataBinding.enabled = true }
POJO
Starting with a quick example, we will use a simple POJO that will store the information:
public class Note { private String text; public Note(String text) { this.text = text; } public String getText() { return text; } }
LAYOUT
Configuring the layout is one of the most important tasks when using Data Binding, as it will enable to define all the rendering aspects of our screen directly in the layout.
This step will also inform the Library that the layout will require the generation of specific Data Binding classes per layout with all the Data Binding abstractions needed, which will also simplify our work with this layouts.
Starting with a regular layout, we need to apply some changes:
We need to start our layout with an additional root tag. The existing Views need to be placed inside a tag. This is what informs the Library that this layout will allow to use data to be bondable to Views.
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="note" type="com.exaud.databinding.Note" /> </data> <LinearLayout … <TextView android:text=”@{note.text}” … /> </ LinearLayout> </layout>
In this example, we are defining a variable note based on a Note Class. In the existing layout we are using the text field from Note to be shown on a TextView.
ACTIVITY
The simplest part of all Data Binding usage is to marvel how simple and clean is to manage the Activity or Fragment:
public class NoteActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityNoteBinding binding = DataBindingUtil.setContentView(NoteActivity.this, R.layout.activity_note); binding.setNote(new Note("test text")); } }
As we can see, this class is very straightforward to configure. The tag on our activity_note.xml layout generates a ActivityNoteBinding class each time we build the application, that contains all the Data Binding magic.
At this stage, we have everything ready to test the example. This is the step that can show us one of the unfortunate problems of using this Library – fixing errors in our code.
As the Data Binding relies deeply on generated classes, we need to be sure that we built the project before trying to access newly added variables or annotations. For some help on troubleshooting common problems, I suggest taking a look at CodePath Android Cliffnotes.
TWO WAY DATA BINDING
Currently, our EditText that contains the text of the Note was in reality just loading the initial data from Note and never afterward updating the Note class with any change.
To fix this, we need to enable two-way Data Binding by changing the way the text variable is being managed on the layout:
… <LinearLayout … <TextView android:text=”@={note.text}” … /> </ LinearLayout> …
Note that the change made was adding an “=” into the expression. This will insure that each time a change is made on the layout, the data is also updated. In order for the data to be changed, we need to add a setter to the text field on Class Note:
… public void setText(String text) { this.text = text; } …
Now the Note instance that is bounded to the layout is updated with any text changes.
BINDS
To enrich our example we’ll add a Title TextView and a Characters Total TextView.
We will generate both the Title and CharCount from the Text, therefore we must add getters on the Note Class for those fields.
… public String getTitle() { return text.split("\n")[0]; } public int getLength() { return text.length(); } …
We need now to add TextViews for this 2 new fields and attach the respective values from our note variable.
… <TextView android:text="@{note.title}" … /> <TextView android:text='@{"" + note.length + " characters"}' … /> …
Notice that, as we had the need to add quotes to the existing expression, the double quotes used to engulf the expression were replaced by single quotes. Trying it out we see that neither Title or CharCount are ever updated. In order to fix this, we need to add a notifying event to these fields. First, we add @Bindable annotation on the Note Class for those fields.
This is used to add these fields to Data Binding generated classes.
… @Bindable public String getTitle() { return text.split("\n")[0]; } @Bindable public int getLength() { return text.length(); } …
Now that we have our new fields bindable we can notify the UI the need to retrieve an updated value from each field, by adding a notifyPropertyChanged() call for each field, each time the Text is changed on the text setter.
… public void setText(String text) { this.text = text; notifyPropertyChanged(BR.title); notifyPropertyChanged(BR.length); } …
Observations
Instead of adding the getters for title and length, we could easily have used Data Binding expressions, with the code from the Note Class, on the layout as following:
… <TextView android:text='@{note.text.split("\n", 0)[0]}' … /> <TextView android:text='@{"" + note.text.length() + " characters"}' ... /> …
After changing the expression, we need to change the Note Class, by changing text field to a bindable field, and call notifyPropertyChanged(BR.text) on text setter, in order to make sure that each TextView bound to the text field gets refreshed.
… @Bindable public String getText() { return text;} public void setText(String text) { … notifyPropertyChanged(BR.text); } …
After seeing how this simple changes could be done, I want to point out that this is actually a bad option on how to use Data Binding. Adding a complex expression to the layout is typically a wrong way to simplify the code. It is preferable to set an attribution to a field on the layout instead of a complex expression in order to make it more readable. Also, this will allow debug and tests to be easier to apply.
I will explain you some more features and give some more tips on how to use data Binding with RecyclerView, on my next post. Please stay tuned and if you have any doubts please reach me by email andre@exaud.com.
Image Source: https://www.kepha.com.br/utilizando-o-conceito-de-two-way-data-binding-no-android/
Comments are closed