I like to write Android apps. A lot.
When I get a new app idea, I get so excited I just rush to my laptop and start coding right away. I get this urge to dump my brain into code immediately. I want to get a feel for my idea, get it on my phone to play with it and quickly validate if my idea was good, bad or needs improvement.
The structure of the code doesn’t matter at this point, it’s just to test out the idea… right? Just start a new project, throw everything in an activity or fragment and go as fast as you can. That was my approach for these prototypes.
While this approach worked great to validate ideas, every time I got back to my code to change or add something to it, I was confronted by a messy ball of spaghetti code… only good to be thrown out.
I even gave up on some promising projects just because of my laziness to clean up that code in order to continue iterating on it.
So I decided I needed a change of mindset.
What if instead of writing these quick and dirty prototypes, I build them in a clean way that naturally scales as I iterate on them? And maybe I wouldn’t have to rewrite everything if the idea pans out.
What if I had a framework that would force me to structure my code, but still focuses on bootstrapping new Apps as fast as possible?
That’s how the idea for Helium was born.
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:
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.
If you want to give Helium a try, head over to the Github repo, where you will find more detailed explanations, the Gradle link to include, as well as lots of examples.
I built a simple and surprisingly pleasant to use News App using Helium. The code is also on the repo, and it’s available for download on Google Play.
This is only the beginning of my open source journey, but I’m excited for the days ahead and would love to hear your feedback! Hoping to add more built-in components, and evolve the library to make it even more useful.
Happy clean prototyping!