Helium is a Model-View-Presenter (MVP) Framework, written 100% in Kotlin. It helps structure code by providing base classes with clear responsibilities, and accelerates building apps by providing ready to use components.

Show me the code

I like to start with the final result, so here’s a working app, displaying 100 Strings in a RecyclerView, in 20 lines of code:

The only custom logic here is the data to display (the MyRepository class) and how to display it (the MyListItem class). The rest is handled by the framework using the built-in ListViewDelegate and ListPresenter classes, which handle loading the data asynchronously, creating the adapter, inflating the views, and even showing a loader and empty view if needed.

Helium comes with built-in components like this for lists and view pager based screens, but it’s also super easy to build your own components.

How it works

Here’s how a basic MVP component is layered with Helium:

Helium data flow diagram

To put it simply:

Presenters are responsible for your behavior logic

ViewDelegates are responsible your UI rendering

Presenters emit ViewState objects, which get rendered by ViewDelegates

ViewDelegates emit ViewEvent objects, which get handled by Presenters

Presenters and ViewDelegates don’t actually know about each other, they only communicate via these emitted objects. This makes it easy to re-use / combine / swap different Presenters and ViewDelegates.

You can use any object to define your ViewState and ViewEvents, I like to use Kotlin sealed classes. Here’s a simple example:

Here’s what a typical Presenter implementation would look like:

Note that the class extends BasePresenter<MyState, MyEvent>, which indicates the type of ViewState this presenter will emit, and the type of ViewEvent it will handle. That is the contract to determine which ViewDelegates are compatible with this Presenter.

BasePresenter extends ViewModel from the Android Architecture Components (recently renamed Jetpack), which allows Presenters to:

React to lifecycle events using the @LifecycleEvent annotation

Persist across configuration changes

The main rule to remember when writing Presenters is that they should never hold references to ViewDelegates, Views or Context.

You can find more information and examples of Presenters on the github repo.

As for the ViewDelegate, here’s a typical example:

Once again, extending BaseViewDelegate<MyState, MyEvent> to define what type of ViewState this class can render and what type of ViewEvent it can emit.

ViewDelegates only responsibilities are to bind views in the render() method according to the current state, and push ViewEvents on user actions.

This separation of concerns is what will keep your prototyping code clean and scalable.

Finally, this is how to use a Presenter and ViewDelegate together and display the component in an Activity:

That’s it! The attach() method is what connects the Presenter and the ViewDelegate, which will then start emitting state and events to each other. Note that there is no cleanup code needed, Helium uses AutoDispose to cleanup the subscriptions under the hood automatically.

The code in Activities and Fragments doesn’t have to be longer than this last snippet, and does not change as your app scales up. All your code should be concentrated in Presenters and ViewDelegates, with single responsibilities.