Managing UI With Kotlin Sealed Classes

Gregory Sosorev
May 6 · 4 min read
Photo by Marc Reichelt on Unsplash

Hello everyone! My name is Gregory, I’m android developer from Moscow. Here is my first article about android app and kotlin sealed classes. It’s a short and elementary example. I hope someone will find it useful and will be glad to receive your feedback and ideas!

In this article I’m going to create a very simple android app to show you an easy way to manage UI with kotlin sealed classes. I have tried to follow base Clear Architecture and SOLID principles but some things like absence of dependency injection, boilerplate code and other minor limitations you will see here in case of simplification the app. The main goal of this short article is to show how we can use kotlin sealed classes and managing our UI in easy and beautiful way.

First of all create the project, open app build.gradle file and add this.

I’m using coroutines and MVVM but you can chose RxJava, MVP etc. Now we need to create some views in main activity xml.

This xml file was created to show the main idea and it is far from perfect. So we have three main views: success_layout, progress_bar and error_layout. Their visibility is gone by default.

Next step is creating MainScreenState class.

All subclasses of a sealed class are known at compile time, so when expression help us write clear and understandable code.

Now we need to create data class for testing.

All business logic will be in a view model. This is a lifecycle aware class that helps us to store and manage data which survives configuration changes such as screen rotation.

In the MainViewModel class we have a repository. In big applications we often need an intermediate layer like interactor or use case to separate logic and responsibility, but a repository is enough for us. A good solution is to inject the repository in a view model by dagger, koin or other dependency injection frameworks.

Next property is a defaultError string. Don’t do it in the real app. A good idea is to inject a custom resource manager class which has a context and can get resources properly in a view model.

Our data holder is a mutable live data. We can easily observe it from activity or fragment and display actual data to the user.

Let’s take a look at the main fetchData method. First of all I’m checking screenState value. If it is already Success in our case we don’t need to continue loading. It’s really a very simple example. Otherwise I’m changing screen state by loading state to show user pending and trying to get data from the repository. We almost always need to do blocking operations when we ask for a data from server or database. Here I use coroutines and viewModelScope extension. In this block of code I can invoke suspend functions — the main idea of coroutines. Delay helps us to test UI but don’t do it in a real practice. All synthetic loading and expectation is a bad decision. As developers we must show information and data to our users as fast as we can. The best solution is to store and display data from the cache and download it from the server at the same time. The next step is obvious — if we get the result we show success, if not we show error.

Have a look at the repository.

We should work with interfaces and hide their logic in implementations to create well-maintained applications. MainApi is an object — anonymous class, realization of interface with a single method. It can be retrofit, database or other sources.

The getData method of MainRepositoryImpl randomly returns user from api or throw Exception.

Usually I use view binding feature to interact with views, but here is an old findViewById solution. First of all we ask ViewModelProvider for our main view model. If it exists we get our model with all data saved there, if not we get a new one. After this I’m starting to observe screen state live data. Because the type of screen state live data is our sealed class we can use when expression without else branches. We are absolutely sure that we can get only one of these three subclasses. Here I hide or show main views such as success_layout, progress_bar and error_layout.

Sealed classes in Android development help us manage the UI and write clear and understandable code. But the design of this app has a big flaw when we are talking about a large project with many screens. The name of this big flaw is a violation of the DRY principle. Each new screen forces us to write repetitive code. If you like this article, I’ll create a new one where I show you how you can gracefully avoid code repetition. Thanks for reading! Here is full code of the project:

Geek Culture

Proud to geek out. Follow to join our +500K monthly readers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store