In Blog Articles

When users open an Android app, what they see is the result of Android developers assigning data from various inputs (databases, the internet, etc.) to elements of the app user interface. Until 2015, the process of assigning (or “binding”) data toxx UI elements was tedious and potentially messy. During its I/O developer conference that year, however, Google demonstrated its Data Binding Library, which gave developers the ability to streamline and clean up the process in many ways.

When the Library was Beta-released later that fall, I was eager to learn more about Android data binding and its applications, but it was still in its infancy and Google’s disclaimer warned against trusting it in any released app. Fast forward two years to today, and the Android Data Binding Library has matured considerably. The disclaimer is now gone, and I recently began exploring data binding in my daily development work.

Like any good Android developer, one of my main goals is to write clean code, code that “never obscures the designer’s intent but rather is full of crisp abstractions and straightforward lines of control,” as author Grady Booch put it. I have found that using data binding with the Model-View-ViewModel (MVVM) architectural pattern and RecyclerView accomplishes many of the objectives of clean coding, including reducing the requirement for boilerplate code, facilitating code decoupling and improving readability and testability—not to mention reducing development time.

Unfortunately, Google’s examples of using data binding in Android apps are rather simplistic and lack detail. So let’s explore the necessary steps to set up a project with data binding, a RecyclerView and MVVM—and write clean code in the process.

A Quick MVVM Primer / Refresher

MVVM is an architectural pattern that was created to simplify user interface programming. Google appears to be encouraging the use of MVVM for data binding. In fact, the Architecture Components of its Data Binding Library are modeled on the MVVM pattern.

The main components of MVVM are the Model, View and ViewModel, and its structure essentially supports two-way data binding between the latter two.

  • The View defines the user interface structure, layout and design and consists of views, layouts, scroll listeners and so on. It also notifies the ViewModel about different actions.
  • The ViewModel serves as the intermediary between the View and the Model. It provides data to the View via bindings and handles View logic. It calls methods on the Model, provides the Model’s data to the View and notifies the View of updates.
  • The Model is the data domain model and the source of application logic and rules. It provides data to the ViewModel and can update the ViewModel using notification mechanisms such as data access objects, models, repositories and gateways.

As you can see, the View knows about the ViewModel and the ViewModel knows about the Model. The Model, however, doesn’t know about the ViewModel and the ViewModel doesn’t know—or care—about the View. This separation enables each component to grow independently, and this design pattern makes the user interface distinct from the corresponding business logic. The result is easier application development, testing and maintenance.

Data Binding with MVVM and RecyclerView

Follow the steps below to set up Android data binding using MVVM and RecyclerView.

1. Update the Gradle File(s)

The first step in adding data binding to a project is changing the module’s build.gradle file(s). Recent updates to the Android Data Binding Library have enabled easier data binding by adding a data binding closure to the Android closure, and because data binding is included in Google’s Application and Library plugins you no longer need to add a dependency. Instead, use the following closure:

2. Prepare Your Tags

To use data binding in Layout Files, you must wrap the normal View Groups or Views in <layout> tags containing data tags with variables for bindable methods and binding adapters. Bindable methods are typically referenced with app:data="@{viewModel.data}", where the “viewModel” variable is the ViewModel, set on the binding (more on that later).

To reference the bindable method annotated with @Bindable, you only need to specify viewModel.data. You can still access methods not annotated with @Bindable by using the full method name, such as viewModel.getData. As seen below, to set up a RecyclerView with data binding, just add a method reference from which to acquire the data.

Activity Layout File

Disclaimer: Some attributes, namespaces, etc. have been omitted to highlight how to use data binding.

RecyclerView Adapter Item Layout File

Disclaimer: Some attributes, namespaces, etc. have been omitted to highlight how to use data binding.

3. Set Up the ViewModel

The way you set up and use data binding is similar for both activities and fragments. Depending on the application’s need for the context, UI and lifecycle, you can reference the ViewModel by inflating and binding the View with the data binding library or by inflating it independently and binding to it with the library.

Next, call the appropriate ViewModel methods from the UI. One way to instantiate the binding is to use the DataBindingUtil’s setContentView method. Calling the binding’s setViewModel method sets the ViewModel variable reference, named “viewModel,” as depicted here:

Clean Coding Tip: Separate concerns and increase readability by providing individual methods for topics such as binding and RecyclerView initialization.

4. Implement the Adapter

When implementing the Adapter, the ViewModel needs to be set for the ViewHolder, binding and unbinding of the View. A lot of online examples don’t show unbinding the View, but it should be done to prevent problems.

5. Notify the Adapter for Data Set Changes

In this ViewModel, the data (items) are made available via the method getData(). When you need to notify the Adapter for data set changes, call notifyPropertyChanged(int) instead of calling notifyChange() (which would notify changes for all of the properties and likely cause issues).

6. Update the Method

This binding adapter method is the other part of the glue to update data in the Adapter. In the MVVM pattern chart, the ViewModel notifies the View of property changes by calling this method. Attribute data is referenced as app:data="@{viewModel.data}" and ViewModel.data references method getData, annotated with @Bindable. When combined with the call to notifyPropertyChanged(BR.data), this reference calls the RecyclerViewDataBinding.bind(RecyclerView, DataAdapter, List), annotated with @BindingAdapter({"app:adapter", "app:data"}).

Disclaimer: Although some readers may disagree with having an adapter reference in the ViewModel, this ViewModel provides notifications to the view. The components can be unit tested individually with JUnit and Mockito and together with integration / UI tests.

DataItemViewModel : BaseObservable

Model

7. Set the Default Component

To reuse data binding code among multiple classes, set your data binding component as the default component as shown below.

Clean Coding Tip: Provide a custom Data Binding Component class so you can abstract binding methods from ViewModels and isolate them for testability. Consider mocking the component class for better testing of the component classes.

8. Set Your Data Binding Class Accessor Methods

The data binding library requires classes using the @BindingAdapter annotation to have associated “get” accessor methods.

AppDataBindingComponent : android.databinding.DataBindingComponent

9. Set the Adapter on RecyclerView

This is where you can set the Adapter on RecyclerView and where adapter updates occur.

10. Click Event Handling

When a click event results in handling data accessible in the ViewModel, the best approach is to set the onClick attribute on the View in the bindable layout with android:onClick="@{viewModel::onClick.}" specified for the View. The ViewModel must have onClick(View) method implemented to handle the click event.

Tips for Keeping Your Code Clean

Some final tips from the trenches for Android data binding:

  • Making extra calls to notifyPropertyChanged(BR.data) or notifyChanged() can lead you down a path of producing bugs, including duplicated data.
  • There is a timing bug with the databinding library and use of ViewModels, extending BaseObservable, where calling notifyPropertyChanged(int) or notifyChanged() results in no action taking place. This occurs because the OnPropertyChangedCallback hasn’t been added yet. Until the bug is fixed, consider using this temporary fix: Add an OnPropertyChangedCallback to the ViewModel for handling the corresponding action. It may help to read the generated data binding classes to better understand the problem.
  • Debugging data binding build issues can be tricky. The error messages don’t provide a clear understanding as what the issues may be. Sometimes, an issue may be due to an incorrect object type passed into a binding adapter method. Other times, an issue may be caused by using data binding methods prior to setting the ViewModel.

At Phunware, we’re always working for better quality code. That means figuring out how to apply the latest technologies (such as data binding) to challenging, often high-profile projects. Interested in joining the Phamily? Check out our latest job openings and don’t forget to subscribe to our newsletter.

SUBSCRIBE TO THE NEWSLETTER

Recommended Posts

Leave a Comment

Start typing and press Enter to search

SDK Download

Choose your desired platform to download the SDK or documentation.


iOS SDK

ANDROID SDK

iOS
DOCUMENTATION
ANDROID
DOCUMENTATION

Introducing Rewarded Surveys!

Monetize users with Phunware's new Rewarded Surveys, a less intrusive alternative to standard ads. Contact us to learn more.



pw_icon_dark_800

Get Our Monthly Newsletter!

Be first in line to read the latest Phunware blog posts, white papers, infographics and more delivered directly to your inbox.





Get Our Monthly Newsletter!

Be first in line to read the latest Phunware blog posts, white papers, infographics and more delivered directly to your inbox.