Android MVI with Jetpack Compose

Luca Nicoletti
The Startup
Published in
4 min readMay 30, 2019
Photo by Luca Nicoletti on Unsplash

This year, at Google I/O 2019, JetPack Compose has been announced. It is still

in an early-exploration, pre-alpha stage.

as stated in the official documentation page. And after digging a little into the demo-preview (which you can download) I completely agree with that statement. It’s missing some basic component and it’s not ready for production nor for simply migrating some part of a perk project.

But that doesn’t really matter. I’m more than happy with what we got so far. I had the opportunity to try it out a little and check the potentials of this new way of building apps’ UI.

Photo by Andrik Langfield on Unsplash

In my opinion, starting with Flutter and then with this library, Google’s trying to port the web-development way into mobile applications. In Flutter everything is a Widget, here instead the components are declared as functions.

This might be a really good start, and will also help to learn Flutter for sure. Once you mastered the idea of building UIs through “composing” components, switching to the Flutter (React) pattern is pretty simple. The paradigm behind building component is not so far away between the two.

Brief intro

JetPack Compose allows you to declare

UI components, including drawing and creating custom layouts.

This mean you could have a function which returns nothing — literally, the function has no return type:

But this function, thanks to the@Composable annotation, allows us to declare a “view” which can be set (it’s drawn actually) via setContent() of the activities.

This is a method that initializes the composable widget tree and wraps it in a FrameLayout.

The usual way

What I’m planning to show you, is how we could implement MVI pattern using this new Jetpack Compose in a fancy way.
Right now, we usually do something like this to handle MVI in Android:

We publish through LiveData<MVIViewState> whatever we fetch from a remote or from local storage (cache that data!) this way:

Then we observe that LiveData from our activity:

The View is responsible to render the UI entirely, which sometimes leads to use logic in the View as well, if-else statements to display or hide something, and that when block, is really frustrating, isn’t it? Why should the View check the state, and render a state in a different way from another one? The View should receive a State and just render it, without performing anything else (in a pure functional way).

Let’s change how we build things!

What if we can change this situation, giving the ViewModel , or way better — the ViewState— the power to build the UI, and letting the View only render it? That’s possible thanks to Jetpack Compose.

HURRAY!

So, what do we need to change?
The MVIViewState class will be a little bit different:

This class is pretty verbose, and there’s a reason for it:ViewState should represent the View , so it should know how to render it, right?
By adding a

function to the ViewState we force every subclass to define it, that means that every child-class will know how to “render” its state. In this way, inside the ViewState class, we build our View accordingly to the ViewState . This will allow us to have a leaner View (Activity or Fragment).

So, what about the ViewModel class or the Activity/Fragment? Well, the ViewModel basically remains the same:

Okok, and the View ?

HERE it is! Isn’t it beautiful?

I personally love how the view just became really lean and basically doesn’t do anything. I̶t̶ ̶o̶b̶s̶e̶r̶v̶e̶s̶ ̶t̶h̶e̶ ̶L̶i̶v̶e̶D̶a̶t̶a̶ ̶a̶n̶d̶ ̶t̶h̶a̶t̶’̶s̶ ̶i̶t̶.̶ ̶T̶h̶r̶o̶u̶g̶h̶ ̶t̶h̶e̶ ̶s̶e̶t̶C̶o̶n̶t̶e̶n̶t̶ ̶{̶}̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶f̶r̶o̶m̶ ̶t̶h̶e̶ ̶J̶e̶t̶p̶a̶c̶k̶C̶o̶m̶p̶o̶s̶e̶ ̶l̶i̶b̶r̶a̶r̶y̶,̶ ̶w̶e̶’̶r̶e̶ ̶n̶o̶w̶ ̶a̶b̶l̶e̶ ̶t̶o̶ ̶d̶o̶ ̶t̶h̶i̶s̶ ̶m̶a̶g̶i̶c̶ ̶t̶r̶i̶c̶k̶!̶

EDIT: thanks to Leland Richardson and his suggestions the View is now even better.

Instead of calling setContent{} several times, it creates the basic component of the view: CraneWrapper , Scaffold with AppBar and then render inside the Scaffold the part of the View which is the right one to render by observing changes on the ViewState .

Downsides

There are some downsides though:

  • Views are not responsible anymore of building the layout
  • There’s no XML file, so you have to find ViewState class, search for the right state you want to inspect, and read, one by one, each component which it builds
  • Layout Inspector does not work. WAIT, WHAT?!? Yes, it doesn't. That’s because Jetpack Compose does not really create views in the view hierarchy, it just draws on canvas, so basically you’re inspecting a Bitmap .

Do we care?

Not at all. Let me explain myself. Those downsides listed above are real downsides. I mean, I would be stuck trying to find out why a click on a component is not working since December if it wouldn’t be for the Layout Inspector.
But since the Viewis not responsible anymore to build the layout, you can easily check how it’s built. You won’t have any more hidden loaders, hidden recyclers, hidden custom views. All your user needs to see, will be built into the “View hierarchy” and drawn on the canvas. You’ll end up having a WYSIWYG.

Conclusions

That’s it! This was just a brief introduction to what I expect it will be the development of Jetpack Compose combined with the MVI pattern in the Android world!

Hope you enjoyed the reading! Every feedback is appreciated (be nice, that’s my first blog post :D).

--

--