Android Data Binding: Dependent Properties

Declaring Instead of Coding the Dependencies

Android Studio 2.3 has been released and I can talk a little about the data binding features that you’ll be able to use with it. One of the cool new things you can do is create dependent properties.

Names, Names, Names

I have a view model representing a user in my application. It contains a first name, last name, user name, and a display name. The UI should update whenever these values change, so I have made it observable.

public class User extends BaseObservable {
private String firstName;
private String lastName;
private String userName;
private Resources resources;
    public User(Resources resources) {
this.resources = resources;
}
    @Bindable
public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
notifyPropertyChanged(BR.displayName);
}

@Bindable
public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
notifyPropertyChanged(BR.displayName);
}

@Bindable
public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
notifyPropertyChanged(BR.userName);
notifyPropertyChanged(BR.displayName);
}

@Bindable
public String getDisplayName() {
if (firstName == null) {
if (lastName == null) {
return userName;
} else {
return lastName;
}
} else if (lastName == null) {
return firstName;
} else {
return resources.getString(R.id.name,
firstName
, lastName);
}
}
}

You can see that the display name doesn’t have a backing field. It examines the other fields and generates a value based on the others.

With my User class, data binding expressions can be written against all properties. Whenever firstName, lastName, and userNames change, expressions containing the displayName will also be updated because I have notified that the displayName changed in the respective setter methods.

This is a common scenario: one property depends on other properties. It isn’t great that the property that is the dependency (e.g. setFirstName()) must also notify that its dependent property changes.

Declared Dependent Properties

In Android Studio 2.3, you can now declare a bindable property to depend on other properties:

public class User extends BaseObservable {
//...

@Bindable
public String getFirstName() { ... }
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}

@Bindable
public String getLastName() { ... }
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}

@Bindable
public String getUserName() { ... }

public void setUserName(String userName) {
this.userName = userName;
notifyPropertyChanged(BR.userName);
}

@Bindable({"firstName", "lastName", "userName"})
public String getDisplayName() { ... }
}

The Bindable annotation now takes an optional parameter to declare dependencies. The displayName property is declared to be dependent on the firstName, lastName, and userName properties. Whenever there is a notified change on any of those properties, expressions with displayName in them will also be refreshed.

The dependency is completely evaluated in the generated binding class. That means that if you attached an Observable to User, you would not get a notification for the displayName when the other properties change.

Using dependent properties can help clean up view models. While the underlying data model is relatively normalized — data isn’t duplicated in multiple properties — the view model is tailored to what shows in the UI. This means that properties often interact with each other.

For example, imagine your UI shows an invoice and your store gives a discount based on the amount purchased. The discount can then depend on the subtotal. Later, if you change your discount to depend on the shipping state as well, you only update the discount property, not the state property.

Dependent properties should help keep your view models a little cleaner and easier to maintain.