New View State arrives…

Android applications which use unidirectional UI archictures (MVI is one of them) usually have UI state passed as a single entity to some kind of a “render”-method. Sometimes it is needed to render only parts of the state which are actually changed.

This can come in handy when your view (model) state changes often and some parts of your UI view hierarchy are expensive to layout again and again or when a view state field change causes some animation to start — you would want it to be done only on actual changes to that field and skipped if other part of a view state has changed.

I wrote a simple library “Diff Dispatcher”, which can help by generating a simple boilerplate code which does all the necessary “change”-checks for the fields of your view state.

To enable generation of state change dispatcher, annotate a data class represeting your view state with @DiffElement annotation:

@DiffElement(diffReceiver = ViewStateRenderer::class)

data class ViewState(

val users: List<User>,

val categories: Map<String, Category>,

val showProgressBar: Boolean,

val showError: ErrorDescription?

)

Next, you will need to provide a diff receiver interface which will be used to generate an actual dispatcher implementation with necessary checks (read further for an example of generated code):

interface ViewStateRenderer {

fun renderUsers(users: List<User>) fun renderCategories(

categories: Map<String, Category>,

users: List<User>) fun renderLoadingErrorState(

showProgressBar: Boolean,

showError: ErrorDescription?)

}

There can be any number of methods in the receiver-interface and they can have arbitrary names, but their argument names must match the names of the ViewState fields.

Note how any field can be used in different methods — this will simply cause the necessary check to be generated, so that method will be called if any of the fields mentioned in its arguments has changed.

The ViewStateRenderer interface above will cause a dispatcher class to be auto-generated which will look roughly like this:

Generated Diff Dispatcher

All you have to do after you add annotation and receiver-interface is to use a generated builder to create this dispatcher for you:

Diff Dispatcher is available as a library on Github. It was made with processing Kotlin’s data classes in mind, but it should also work for Java classes (although it’s not as thoroughly tested on java classes yet). If something doesn’t work, please create an issue.