Paradigm shifts with declarative UI
Declarative UI is not a new concept in the development world, but it’s lately gaining momentum on mobile native SDK, probably after a few other cross-platform frameworks started exploring these approaches. Learning how to use them implies changing the way we imagined layouts, and overall graphical user interfaces, for the past years.
As SwiftUI approaches on iOS, Jetpack Compose is being built in the open for the Android ecosystem.
At the time of writing, Jetpack Compose is still being heavily developed, and many things change by the day.
I wanted to give Compose a try and use it to create a small app that, given the Lego set number, will retrieve the basic information of such a kit: a picture, the title, and the link to the instructions.
Overview of the functionalities
As a developer, it’s pretty easy to highlight the main points in the aforementioned example:
- A network request is needed to fetch the data from the web
- The backend will most probably return a link to the image so that it has to be downloaded later
- Data should be displayed on a list
Inside the comfort zone
Being familiar with the Android ecosystem, I pointed myself in the direction of using a whole bunch of well-known libraries to help me get the job done, and those include RecyclerView, Retrofit, KotlinX Serialization, Picasso, and Dagger.
The use of a dependency injection framework such as Dagger might seem overkill for such a small app, but in a real project, it should be the go-to for building your objects. In this case, using such an articulate framework that involves the use of kapt could cause a conflict with the Kotlin plugin needed for Compose, so I decided to put both into the mix and see what happened.
The important bit is the use of Picasso (or any other image downloading tool): we normally would call it as close as possible to the view layer, as each of these libraries works best with a reference to the
View where the image will be downloaded.
The new way(?)
As of today, there is no easy way to provide an image asynchronously with Compose. It is certainly being worked on (as we can understand by the comment left in the code, at least for what concerns loading from resources), but it’s not present in the SDK just yet:
In an ideal world, I would expect to tell an
Image where to fetch its content from and it would automatically show it for me, but it is not yet the case. It wasn’t until now, and it’s certainly not yet the case.
So, I decided to try something different, that could be easily replicable again. Instead of passing down the URL, I would wrap the Picasso call inside a coroutine and download the images before I send the model to the UI, right after the API call:
The good, the bad, and the ugly
While this solution works (good), it is a feasible procedure only when we know that the amount of images we are downloading is fairly limited (bad), and it is overall a bad practice (ugly): we don’t want to fetch more data than the amount our users will see, and we certainly would prefer to download the images in a separate chain.
One more thing…
Another thing that hit me (in a positive manner indeed!) is the fact that
Composable components do not manage the state: as of now, every change to the state should be managed from a specific object, that should be tied to the
Composable. Let’s see an example:
The important part is related to line 6: if we removed the
onValueChange parameter as a whole, we wouldn’t be able to either see what was being typed inside the text field. This is, in my opinion, a huge leap forward: with the current approach, it’s never clear where and when the state of a
Widget is saved and updated. Managing the state of a
View is no easy task, but the path drawn by declarative UI frameworks will make developing graphical interfaces easier and less chaotic in the long run.
It is an easy solution (most certainly there are other ways to perform the same task on the web) to a problem that I was facing, and it made me realize that declarative UIs, such as Compose, are bringing a shift in the way we shape our code, and this is something to keep in mind.
Furthermore, with this approach, we are certainly closer to the real idea of a
ViewModel compared to what we do now, but I’m sure this is only one of the millions of small changes that this new wave of UI frameworks.