https://www.flickr.com/photos/75487768@N04/16741949632

Add the new ViewModel to your MVVM

Danny Preussler
Google Developer Experts

--

Google announced at I/O a set of architecture components. These included a ViewModel, a class your views would bind to, so that the data the view model contains would survive a screen rotation for example.
That sounded great for developers that use MVVM. Getting the view model that we need anyway with the ability to survive orientation changes, that sounds too good to be true.

But can it be be easily adopted into a real word app?

I took our Playplex app at Viacom, the base for successful apps like Comedy Central, and tried to adopt it to our shows screen, a list of TV shows. The implementation is already based on MVVM with a ShowsViewModel for the fragment and another view model for each RecyclerView item.

The steps

What do we need to do?
First extend your existing view model class by ViewModel or AndroidViewModel if you need the application context.

public class ShowsViewModel extends ViewModel {

Next find the place where you create your view model, probably in a Fragment or Activity, and replace the new for the mode with a method call to ViewModelProviders

ShowsViewModel createViewModel() {
return ViewModelProviders.of(this).get(ShowsViewModel.class);
}

This will either create one for you or reuse an existing one.

But what if …

But probably your constructor was not empty:

ShowsViewModel(ShowsUseCase useCase) {
this.useCase = useCase;
}

What to do?
You can implement a provider factory that knows how to create view models.
This one could then even use dependency injection to get everything you need. This way you move the responsibility of creating view models into a separate class which already made your code better (single responsibility principle).

class ShowsViewModelFactory implements ViewModelProvider.Factory {

private final ShowsUseCase useCase;

@Inject
public ShowsViewModelFactory(ShowsUseCase useCase) {
this.useCase = useCase;
}

@Override
public ShowsViewModel create(Class modelClass) {
return new ShowsViewModel(useCase);
}

}

and adopt the call to ViewModelProviders

@Inject ShowsViewModelFactory factory;
...
ShowsViewModel createViewModel() {
return ViewModelProviders.of(this,factory)
.get(ShowsViewModel.class);
}

That’s it, you’re basically done!

No more life cycle forwarding

But probably you have some methods to clean up. If you forwarded lifecycle events to the view model from Fragments or Activities, these probably can be removed. The whole idea is that you don’t care about those any more as the view model will not get destroyed on configuration change.

Don’t worry, you still have the possibility to release resources when the Activity gets completely destroyed. Simply override onCleared() to cancel long running operations for example:

@Override
protected void onCleared() {
super.onCleared();
cleanupSubscriptions();
}

Keep the flow right

I hope you never passed any View or Activity into your view model. This will cause a leak now, so try to avoid that in any cases as it’s also not how MVVM should work!

Databinding

So what if you use Android data binding? Does it work?
Indeed it does, the basic sample from Google already builds on top of that.
In data binding you have different implementations how the view gets notified on changes on the items its bound to.
You either expose public instances of ObservableField or bind your views to methods not fields and use notifyPropertyChanged manually to notify a change. If you use the first approach, there is nothing you need to change. The second approach is a bit problematic. Here your class already extends BaseObservable a nice convenience class for the notification code. As Java does not allow multiple inheritance you can not have both, the ViewModel and the BaseObservable. But don’t worry, Eric Richardson suggested a (not so) nice workaround here:

Copy the code from BaseObservable and let your version extend ViewModel:

public class BaseObservableViewModel extends ViewModel implements Observable {

private transient PropertyChangeRegistry callbacks;

public BaseObservableViewModel() {
}

...
}

This way you get both worlds. That’s all the change you need. (Jose Alcérreca promised it will be fixed in the future, so see this as temporary workaround)

All the things?

So do you now have to move all your view models to the new class structure? Actually not. Let’s assume you use view models in a RecyclerView for each item. These probably don’t hold the data individually but there is a broader collection for it. These small view models can stay as they are as long as they are not bound to the life cycle of the activity or fragment. So be careful here.

Conclusion

Was the ViewModel the missing link for our MVVM implementations? I think so and migrating to it is pretty straightforward.

--

--

Danny Preussler
Google Developer Experts

Android @ Soundcloud, Google Developer Expert, Goth, Geek, writing about the daily crazy things in developer life with #Android and #Kotlin