My take on Model View Intent (MVI) — Part 1: State Renderer

Written by ZakTaccardi | Published 2017/03/30
Tech Story Tags: android | android-app-development | software-development

TLDRvia the TL;DR App

Automate UI testing with predictable state and flexibility, off the UI thread

Goals

  1. Fully automate UI testing (Espresso on Android)
  2. All computation (except view access) done on a background thread
  3. A front-end architecture that can fit any platform. The same ideas apply to iOS, Android, & the web, thanks to ReactiveX’s cross-platform nature.
  4. A UI layer that can adapt to anything. Edge cases, new requirements, and increased complexity do not require refactoring

This article covers goals #1 and #2. In a future post, I’ll dig into why #4 is true.

Model View Intent (MVI)

I definitely recommend checking out Hannes Dorfmann’s amazing blog series on MVI and Android. I won’t get in to what Model View Intent is, but rather my specific implementation of it.

In a nutshell, we will merge input from our data layer with user input to output a continuously updated ViewState over time, rendering each new instance of a ViewState onto our Ui/View.

Demo App — a “Deck of Cards”

Here’s the simplified implementation ofStateRenderer<DealCardsUi.State>.

Using Rx’s Schedulers and observing the latest ViewState, we achieve Goal #2 — stay off the UI thread as much as possible.

Automated UI Testing

All of our Ui classes have the following function — a single point of entry for displaying information to the user.

fun render(state: ViewState)

Testing is reduced to a simple input/output function.

  1. Input — the ViewState. Grab a reference to your Ui, and call the ui.render(viewState) function.
  2. Output — the Ui. Use Espresso to verify the Ui looks as expected.

Want to test configuration changes? Call activity.recreate() and verify the output is unchanged again.

Meet the following requirements to simplify testing.

  1. Unhook (disable) every Presenter from activating during testing, and/or disable your disk/network layer.
  2. Keep navigation functional without presenters. Navigation via intents simplifies this.
  3. Ability to get a reference to your view. This could be an Activity, Fragment, ViewGroup, Controller, etc - but you must be able to call your view.render(state: ViewState) function.

Conclusion

I truly believe this style of view architecture is the natural evolution over MVP, MVVM, etc. A single ViewState allows for predictable state and maximum testability.

In future articles, I will dig deeper into other components, such as the business logic that is responsible for the ViewState.

Catch the conversation on Reddit

All source is available on GitHub.

Shoutout to the many pioneers of reactive programming that have made this architecture possible!

Additional resource — watch Jake Wharton’s awesome talk on managing state with Rx.


Published by HackerNoon on 2017/03/30