Monday, May 22, 2017

Data Binding with Android Architecture Components Preview

In the talk Architecture Components – Solving the Lifecycle Problem from Google I/O 2017, Yigit Boyar talked about the new LiveData<T> class of the Architecture Components library. When talking about it it’s always coupled with the concept of the ViewModel. I’ve long been a fan of the MVVM pattern when doing mobile development so this was interesting to me. I’ve also been using the Android Databinding framework, so I was interested in seeing how this plays together.

tl;dr: Right now, they don’t. But let’s dig a bit deeper.

LiveData vs ObservableField

LiveData<T> was presented in a slide as:

  • An Observable data holder
  • Lifecycle aware
  • Automatic subscription management

In android data binding we find the sister class ObservableField<T>. If I were to write a similar slide for that one, it would be:

  • An Observable data holder

The difference is that ObservableField<T> isn’t lifecycle-aware and hence there cannot be any automatic subscription management. However the Android Data Binding framework does the subscription management for you – it’s just not directly aware of the lifecycle. Instead of immediately unsubscribing when a fragment pauses or stops, it has somewhat of a delay. Notice this memory dump from a bound ObservableField:

You see that the mListener is a ViewDataBinding$WeakListener. If you look at the ViewDataBinding class inner workings, you see that it uses a WeakReference to the views and view bindings. This ensures that whenever an Activity or Fragment is dead, the reference to the ViewModel and its ObservableFields are removed in due time. Just not immediately as you would get if it was lifecycle aware.

Using it with data binding

So the key question is – can we just swap all usages of Observable<T> with LiveData<T> in view models we use with Android Data binding? After all, they’re just observables with life cycle awereness.

Alas: No.

In the Android Architecture Components Sample app, it’s implemented rather cumbersome with boilerplate code which pipe data from one type of observables (LiveData) into another (Observable). This is why:

  • LiveData<T> cannot be bound to directly in XML.
  • The Android Data Binind framework doesn’t know how to observe on LiveData.

The first bullet point is easily fixable. We could just write a simple converter. The second one is not as simple though. At least not for us laymen. Google could fix it, and I hope they will. Notice the difference in the interfaces for subscribing on the two classes:

ObservableField.addOnPropertyChangedCallback(Observable.OnPropertyChangedCallback callback);
// versus
LiveData.observe(@NotNullLifecycleOwner owner, Observer observer)

You have to provide the LiveData-object with a LifecycleOwner. Per now, the Android data binding framework isn’t rigged to do that. But it could be, and I hope it will be soon. I notice that it’s Yigit Boyar who present these concept – the developer who’s also behind Android Data Binding. He should know how to tie these things together.

The ViewModel holder

Another interesting class introduced in the Android Architecture Component talks is ViewModelProviders. I’ve found it does three things:

  • Retains view models across device rotations and other lifecycle-affecting events
  • Rids of the view models on onDestroy
  • Saves and restores the view models helped by the Parcelable interface on onSaveInstanceState and onCreate *

*) Disclaimer: Very superficial research done here

The problem it solves is avoiding double calls to expensive services when a long-running request is interrupted by a lifecycle change. Illustrated by this slide in the talk, just to set the context:

image

I’m claiming that this class bring more value to the table for data binding users than the LiveData-class. It wasn’t very difficult to achieve before either, though. The Data Binding framework already allowed for this pattern as long as you implemented the holder class yourself.

Example: I made an improvement to my earlier MVVM example project where I’ve introduced a holder for the ViewModel-class accessed through a application-wide singleton. There wasn’t a lot of code change needed. You’ll notice after this commit that the “# logged in users” in the top right corner of the example activity doesn’t reset after device rotation using this technique – even if you interrupt the 2 second long initial load.

In the branch androidarch I solved the same problem using the ViewModelProviders-class from the Architecture Components. I also experimented with binding to a LiveData class instead of ObservableField, but found it not to bring any value to the architecture or solution due the arguments stated above.

Conclusion

I think the Android Architecture Components is a good set of components that for sure will make it easier for new developers to create a solid foundation from the start. The earlier examples from Google have rieked of bad practices and been riddled with pitfalls. But in terms of the interoperability with Android Databinding it seems very unfinished. Maybe they hoped to get it more done for Google I/O than what was presented. In any case I look forward to the next versions of this library and its migration into the support framework.

No comments:

Post a Comment