If you have been in the Android ecosystem for a while, there is a chance that at some point you needed to show a list of items on the screen grouped by a given criteria in the form of a header. Something like:

Language list grouped by type

We can identify two different types of rows on the screen:

Header : it contains the language type name.

: it contains the language type name. Language: shows the data for a given language (name, latest version and release date).

Let’s start defining the necessary base classes:

Based on that Language class, we will need to show the languages grouped by the type property. We assume that this class represents an entity as part of our domain, which is not coupled to the UI. This is very important because defining models just for the UI will make our lives easier (to change).

The UI is based on a RecyclerView containing two different types of rows. That looks like a sealed class:

Note that in addition to the two classes (each of them representing UI state data), there is also a new enum RowType that we will later see why will it be useful.

Now we can start building our adapter using the newly created classes. We are lucky that RecyclerView.Adapter class already comes with support for different types of views: the getItemViewType function allows defining which type of view will be used for a given data row index (this is where the enum becomes handy):

So for now, there is the adapter containing a list of LanguageRow items (remember that this is the sealed class) that is returning the ordinal value of the RowType enum for the getItemViewType function. This is where the power of the enum comes into place as we don’t need to write any if/when statement.

Next, we need to work on Adapter’s holders. The idea is to have two separate holders. One of them for the “regular” rows containing the language data, and a second one for the header:

We can complete our adapter implementation that was missing both the onCreateViewHolder and the onBindViewHolder functions:

There is one important thing here that is still missing. At the beginning I showed a Language class part of our domain, and then the LanguageRow sealed class. But somehow we need to make a transformation to convert a list of languages into a list of rows for the UI. For that, we first need to group languages by the type, and for each of the resulting groupings create a header + all the languages for the current type:

Conclusion

Using the power of the type system will make your code stronger, harder to break and easier to change. Small things such as using enums or defining sealed class to represent a value that is only valid as a part of a set will be more concise and less error prone.

See you on the next article!