Jetpack compose is a modern Android UI toolkit introduced by Google. It simplifies the app development process and speeds it up. With Jetpack Compose, you can write less code compared to the current view building approach – which also means less potential bugs. There is one more great thing about it – it uses Kotlin. If you have been using React or Flutter, you will probably be familiar with the concept and find many similarities.
How does it work?
A main building block of Compose is the Composable function. It emits a part of the user interface. Building with Compose is about nesting the Composable functions in each other.
The declarative approach
Jetpack Compose is built upon a different programming paradigm. It uses a declarative paradigm. To put it shortly, it means that you have to change your way of thinking from: “How to do something” to “What goal I want to achieve”. In a declarative way of programming, you try to describe an expected result instead of describing every step to achieve the goal. In the previous example we simply said “I want to have a column with three texts inside” – and that is all. We don’t need to write any extra code that tells the app how to deal with the items inside the column.
In the current imperative approach, things are a bit more complicated. To render a list of elements, RecyclerView is used. It is a component that helps efficiently display large sets of data. The problem is that each RecyclerView needs an adapter, each item on the list needs a ViewHolder, and so on. An adapter is a place where programmers have to describe how RecyclerView is going to render each element. And if we want to render different types of data, it can be a little messy. For instance, if you want to display text, image, and your custom extended view, you have to write a logic to tell the RecyclerView how to do that. As you can see, it’s beginning to look a little complicated and it’s the exact opposite of the Jetpack Compose and the declarative approach. After all, we only want to create a list with some elements inside. With Compose, it is simple as:
Jetpack Compose ❤️ Kotlin
One of the greatest advantages of Jetpack Compose is that it uses Kotlin. What does it mean for you? Well, for example, you can use all Kotlin structures directly in your view code. You can use If statements to choose what should be rendered, and you can use loops to display a view multiple times. You can also use functional methods like filter, map, and many others.
As the picture above shows: it is really simple to choose what should be displayed, depending on the data set state. If it is empty, show a text saying “No data to display”, if it is not, map the data set elements to Composables and display those in a column.
Updating a view is a crucial task of every single application. It’s hard to imagine the app which shows you the same data all the time. To update a view in Compose, we need to rebuild Composable functions with different sets of arguments.
This process is called recomposition. The question is “How does a Composable function know when to rebuild itself?”. The answer is – because it can have a state.
The state is a value, or multiple values, assigned to a Composable function. Whenever the value is changed, it triggers a recomposition process and our composable function will be rebuilt with a new state value.
In this example code, we can see one state value – counter. The value of the counter is displayed using the Text Composable. Every time the state is changed, this composable is rebuilt with a new value assigned to the counter variable. In Button’s onClick method, the counter state value, which performs the decomposition process, is incremented, and a new value is displayed with Text.
Pagination with Compose
Let’s take a look at a real example that shows how Compose can speed up our work and make it much easier. We are going to compare two solutions for one problem – pagination. We are going to use the current view building solution and Jetpack Compose.
What does pagination mean?
Pagination is a process of dividing a big data set into smaller chunks. It is useful when we don’t want to serve all data at the same time. It could seriously harm our app performance. The Facebook app is a perfect example – usually, when using the Facebook app, you are scrolling your wall and reading new information. Have you ever reached the end of it? Probably not. It seems endless, which means that there is a huge amount of data to display there. Imagine what would happen if we got all that data at once – it would be an overkill for our device. This shows that your Facebook wall uses pagination. The data is fetched in smaller chunks and displayed on the screen. When you are about to reach the end of the current chunk, a new one is obtained from the backend – and so on.
I want to show you how easy it is to implement pagination when using Compose, compared to the current approach. First of all, let’s see what we need to support pagination when using the current view building methods:
- RecyclerView – responsible for displaying the data
- Adapter – displaying logic
- ViewHolders – keeping views references not to use findViewById() each time to obtain them. It would be really costly.
Usually, we want to somehow indicate that data is being fetched. For instance, we might want to show a progress bar as the last element of the list. With the current approach, it is a slightly complicated task. You have to put a new element into your data set and force the RecyclerView to render it as a progress bar. There are many ways to achieve that. Usually, you end up with a lot of new code. Each new view type makes your adapter more complicated. With Compose, implementing pagination is really simple – it only takes a few lines of code!
Let’s have a look:
We can see a ComicsResultSection composable here, which is responsible for displaying our data. The data set that should be displayed is passed as an argument – data. By using a LazyColumnForIndexed Composable, we can present our data as a list. LazyColumnForIndexed is an equivalent of RecyclerView –it renders only the data that is visible on the screen. Additionally, LazyColumnForIndexed gives us information about the currently rendered objects and their indexes. By using the index, we can simply check if the currently rendered object is the last in our dataset. If so, we can simply trigger the data fetch method and display a progress bar as the last element of our list. And this is it. No adapters and complicated logic necessary – we simply say what we want to see on the screen.
Jetpack Compose is a promising and powerful modern UI toolkit that you definitely should keep an eye on. If used correctly, it can speed up the development process and reduce the size of the app. Moreover, with Compose you write less code – which, potentially, means fewer bugs. Happy coding 🙂
If you want to learn more, see the official Compose website: