Introducing Mavericks (MvRx) 2.0
By: Gabriel Peal
Tags: Kotlin Coroutines, Android, Mavericks, Mvrx, Airbnb

Today, we’re excited to announce the release of Mavericks 2.0. Mavericks 2.0 is a ground-up (but fully backward compatible) rewrite of MvRx 1.0 built for Coroutines, with an entirely new world-class testing suite and a revamp of our documentation that makes it easier than ever to get started.

Mavericks tl;dr

If you aren’t familiar with Mavericks, it is a framework built on top of Jetpack ViewModel. Instead of exposing individual state properties, your ViewModel is generic on a single immutable data class that your ViewModel updates and your UI renders. It also contains tons of goodies such as automatic lifecycle handling and easy mapping of async operations to state and a comprehensive testing suite.

Mavericks was built with developer productivity and consistency for large codebases in mind and has been successfully used at Airbnb, Tonal, Dropbox, Wayfair, Kiva, as well as countless other companies.

Personally, I’ve never enjoyed writing Android more than I do with Mavericks.

MvRx -> Mavericks

Once upon a time, RxJava was the beloved standard of asynchronous programming on Android. Today, most apps are transitioning to coroutines. We felt that the original name was too tightly coupled to RxJava (and hard to pronounce) so we’re expanding it to Mavericks.

All artifacts are now published under the mavericks name.

The mavericks-rxjava2 artifact contains backward compatible class names but the primary mavericks artifact has been fully migrated.

RxJava -> Coroutines

Mavericks 2.0 has been entirely rewritten in coroutines.

The primary artifact no longer has a dependency on rxjava at all. A new mavericks-rxjava2 artifact exists for full backward compatibility. It is designed to be a drop-in replacement for existing apps that use MvRx 1.0.

Names like subscribe are now onEach and accept suspending lambdas.

When onEach emits a new value, if the previous lambda hasn’t completed, it will be canceled (aka it behaves like mapLatest).

ViewModel.stateFlow returns Flow<S>.

ViewModel.awaitState() suspends and returns S after all pending state updates are run.

APIs that returned Disposable now return Job.

New Documentation Site

New to Mavericks or just warn to learn more? We decided to rewrite the documentation from the ground up for 2.0. It can be found at https://airbnb.io/mavericks and additions can be made by putting up a PR to any of the markdown docs.

Testing, Mocking, and Launching

Mavericks 2.0 now includes a mavericks-mocking library. Mavericks is built on the principle that a screen is a function of its state. Mavericks 2.0 ships with a new mavericks-mocking artifact. Once enabled, it lets you capture the state of any screen at a specific point in time.

That captured state can then be reused to relaunch the screen in that state at any point (via mavericks-launcher) or be reused as test fixtures. No more clicking through 50 screens every time you build a new app just to test a feature deep in a flow. Now, you can visualize and test any permutation of any screen with ease. Eli Hart has written a comprehensive Medium series on how Airbnb is using it.

Refer to the docs for more information.

Jetpack Compose

One of the most common questions we get is “Will Mavericks work or still provide value once Jetpack Compose exists”. The answer is yes!

In a Compose world, you still need a place to handle complex business logic, do dependency injection, and share data across components. There is a reason that Google provides ViewModel interop out of the box. We are still exploring exactly what the API for Mavericks will look like but rest assured, it is coming. We have already spent some time with Leland Richardson exploring what the ideal APIs might look like and this is an early preview which you can already experiment within your own apps:

You can check out the full gist here.

Dagger and Hilt

Mavericks works great with pretty much any dependency injection system including Dagger and Hilt. With the 2.0 release, we’ve updated our Dagger and Hilt samples to use Dagger’s new assisted injection feature and have an equivalent to Hilt’s ViewModelComponent which makes it easier than ever to integrate Mavericks with Dagger.

Check out our Dagger and Hilt samples.

Jetpack Navigation

Mavericks 2.0 now has a mavericks-navigation artifact for Jetpack Navigation that lets you create nav graph scoped view models.

Epoxy

Airbnb heavily relies on Epoxy for its UI. As a result, most of the documentation and examples for MvRx 1.0 leaned on it heavily. Although the two libraries work great together and Airbnb still relies on both on nearly every screen, there is no explicit dependency between the two. Mavericks can integrate with nearly any architecture or library that exists today and we have removed Epoxy from many of the samples to make understanding Mavericks easier.

State of Mavericks 2.0

Mavericks 2.0 is already running in production at Tonal, Airbnb, and Dropbox for well over 1,000 unique features. Give it a shot and let us know how Mavericks is working out for you!

Thank You!

Mavericks 2.0 was made possible by direct contributions from Gabriel Peal and Denis Bezrukov on core APIs and coroutines implementations, Eli Hart and Mike Nakhimovich on mavericks-mocking and mavericks-launcher, and Mitchell Tilbrook on mavericks-navigation.

And finally, we want to thank everybody who has used MvRx and Mavericks over the years. Your feedback and encouragement have been an incredible driving force in the road to 2.0.