An Untold Story of Observable Dependencies in Data Binding

Muthu Raj
AndroidPub
Published in
3 min readApr 24, 2019

Hope you all heard about data binding. If not, head out here and check it out.

So one usage of Data Binding is replacing findViewById and another one is, binding data obviously.

The true power of data binding comes when we use it with Observables (ObservableInt, ObservableBoolean, ObservableField etc..). Instead of binding data using regular fields/methods, if we binding it using Observable types, UI will be automatically updated whenever we change the Observable values using set() calls.

But what if one Observable depends on another Observable to get its value. Let’s take an example of updating text of an TextView using an ObservableField<String> and updating it’s visibility based on whether it have any text or not.

To update visibility, we would have another field of type ObservableInt (which can hold View.VISIBLE or View.INVISIBLE or View.GONE).

Now how would we update the textVisibility? Whenever we update text? That would be quite a boilerplate and not exactly foolproof because if we have multiple Observables depends on multiple other Observables, even if we forgot to update one Observable in a place, there would be an issue. We can do better.

Let’s step back a little bit and think about what we actually want to solve. textVisibility should be updated whenever text value is updated. That’s all.

Observables can depend on other Observables and can react to changes from the dependents.

This change was done with Android Studio 3.1 release last year.

The ObservableField class can now accept other Observable objects in its constructor.

With this, we can pass other Observables as dependencies when creating Observables which can react to changes when the dependent Observable change. So, instead of this,

we can do this.

You might think the code actually got bigger due to the ObservableInt anonymous class creation, but those can be abstracted away into an until function. The thing is, now we are not updating the textVisibility manually.

Data Binding Extension: map

To abstract the object creation part away and to make the dependency thingy more functional, I wrote an extension function for that.

Does the method name look familiar? You would have seen this name often if you used RxJava or Kotlin collection utils. Since we are transforming one Observable field to another, the name suits here perfectly.

Now the TextViewModel.kt would be like this

You might notice that the textVisibility type is now changed from ObservableInt to ObservableField<Int>. This is because of the return type from map function and we made that way because we need to map function to work will all Observables. Of course, you can make another function that does the same and return ObservableInt if you want.

Let’s take an another case where we do some form validation and submit button should be visible only if all fields are filled.

This is just an example, but in real project, we won’t have these update* methods and those fields would get the latest value directly from the EditText through two-way binding. In that case it gets more tricker since we have to add PropertyChangedCallback to each Observable fields to know when update happens and we should call the checkAndUpdateSubmitButtonVisibility method there. I’m not gonna show the code for that, because, as you can image, the code would be quite a lot.

Now we can simplify and solve the boilerplate issue with our Observable dependency concept.

Let’s write an util extension function for this too.

Data Binding Extension: combineLatest

Again, this function name is inspired from RxJava combineLatest operator. Now the ViewModel becomes,

Note that, the combineLatest method we created here only works with this example where one Observable depends on three other Observables because, we get all the Observables as individual parameters instead of vararg since we can’t deduce the type of each Observable from vararg and each Observable can have different type.

--

--