Android Data Binding: Let’s Flip This Thing

Get That User Input Back Into The Application

So far, I’ve shown how to use Android Data Binding to put information from your application into the UI and bind UI events to your application. We often want a very simple thing: get the data that the user enters back into the application model. Android Studio 2.1 introduced two-way binding to make this much easier.

Two-way Binding

Let’s imagine we have a form for the user to fill out that includes an EditText for the user’s first name. One-way data binding works like this:

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:id="@+id/firstName"
/>

Normally, you’d let the user type in the data and then submit the form. Or maybe you would get extra fancy and strap on an afterTextChanged listener to update your model. Instead of attempting this, you can use the two-way binding operator “@={}” to automatically update the view model with the user’s changes:

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={user.firstName}"
/>

Since the model is updated as the user types, I no longer need to actively retrieve the name from the EditText. I also removed the ID because it wasn’t needed anymore.

Two-way binding doesn’t work for every attribute — only the ones that have event notifications for changes. Fortunately, this includes pretty much all the ones you really care about for user input. Remember, Android Data Binding is designed to work for all versions back to API 7, so it doesn’t rely on any new framework changes. Otherwise, two-way data binding would be supported on nearly every attribute as we could add notifications for the missing attributes.

View Attributes

Now you can also access View attributes from your expressions, just like properties in your data model:

<CheckBox
android:id="@+id/showName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:text="@{user.firstName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{showName.checked ? View.VISIBLE : View.GONE}"
/>

In the above layout, the TextView showing the user’s first name will be visible only when the showName CheckBox is checked. This works when referencing two-way bindable attributes. It also works with any attribute that has a data binding expression:

<CheckBox
android:id="@+id/showName"
android:focusableInTouchMode="@{model.allowFocusInTouchMode}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:text="@{user.firstName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusableInTouchMode="@{showName.focusableInTouchMode}"
/>

Sure, the above example is meaningless, but it demonstrates how to use this type of expression chaining.

Under the hood, the data binding framework sees the “showName.focusableInTouchMode” and recognizes that as data bound to “model.allowFocusInTouchMode” and does a simple substitution.

View References

Another nice thing is that you can also reference Views by their IDs in your event handler lambda expressions:

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/firstName"
android:text="@={user.firstName}"
/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="@{()->handler.checked(firstName)}"
/>