LiveData 💔 Null-safety

Image for post
Image for post

TL;DR

Generics nullability

An example of UI flow for user profile

This example probably looks too familiar to you. But here is the question: What’s the type of the lambda parameter profile at line 8?

The answer in Kotlin is a platform type: Profile! while the answer in Java is Profile. To handle the nullability and take Kotlin-interoperability into consideration, nullness annotation is recommended for Java code. So the polished answer could be @Nullable Profile or @NonNull Profile.

Problem

In a real-world production code though, the null checks quickly grow into an exponential problem. A page may allow the user to paginate, also model repository response as a Resource with loading, success, and error states, we may end up using a type like LiveData<Resource<PagingList<Profile>>>, to represent the search result of people.

Now the question is how to handle the nullness of the type above: LiveData may hold a null Resource, Resource may hold a null PagingList, PagingList may hold nulls in the item list. Our NPath complexity can grow exponentially! 🤯

When I inspected our codebase, I found 5 different teams writing different utility classes, as their attempts handle such nullness in a seemingly standardized way. Nonetheless, among these utility classes, there are always subtle differences so that they cannot be unified easily without behavioral change. The caller code looks fragmented and not elegant, and people need to learn to use the correct utility when working across the app.

Can we write elegant code, which does not perform null checks and optimistically assumes that the value is always non-null? The answer would be a conservative yes unless we find evil writers invokes setValue(null)

It is nearly impossible for us to exhaustively confirm that there are no such invocations setValue(null). We might be able to search through our codebase, but it is not always feasible to search for all the libraries that we are depending on.

The conclusion arrives that if the generic container type is defined in Java, like LiveData or PagingList, we recommend performing null checks to write defensive and safe code.

The silver lining

With the declaration above, we can now enjoy the null elegance with null-safe Kotlin compiler! 🎉

In case we do want to allow setValue(null) for semantic reasons, we could declare LiveData2<String?> to inform all the observers that null need to be handled.

Take away

I would like to thank my colleague Curtis for inspiring this discussion and sharing his insights.

Android Developer@LinkedIn

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