Cinnamon logo
Cinnamon logo
Cinnamon logo
Close

Home

Projects

Services

About Us

Careers

Blog

Let’s collaborate

Close

Getting started with Jetpack Compose

Antonio B.

2019-11-19

5min

Development

You may ask yourself why should you start using Jetpack Compose. Keep on reading and get familiarize with this new Android UI toolkit.

placeholderGettingStartedWithJetpackCompose.jpg

Share this blog:

twitter logo
facebook logo
linkedin logo
link logo

Why Jetpack Compose?

This year, during Google I/O 2019, the Android team announced a new modern toolkit for building native Android UIs called Jetpack Compose. It is based on the declarative programming model like Flutter, React, Litho and others. Jetpack Compose is built in Kotlin that is fully interoperable with Java and also compatible with the old UI toolkit which gives you the possibility to mix both of them. At that time, when Jetpack Compose was first introduced it was hard to experiment with it because you had to build your version of Android Studio. However, a few months later on Android Dev Summit, Google introduced a new Android Studio 4.0 which contains Jetpack Compose. Besides that, the newly released Android Studio 4.0 brings you a live preview to immediately preview your Compose UI. Now it is a lot easier to experiment with Compose. All you have to do is to download Android Studio 4.0 which can be used alongside your latest version of Studio and everything needed to play with Jetpack Compose will be set up for you.

You may ask yourself why should you start using Jetpack Compose. Here are the answers why:

  • The current UI toolkit was written long ago and needed to be written all over again from scratch because adding new features to the current toolkit is hard and also, new features would introduce more bugs

  • Jetpack Compose is fully built using Kotlin. You already know that Kotlin brings us conciseness and safety which means we have to write less code. Less code means fewer errors.

  • Everything is Kotlin. There are no XML files anymore. For instance, previously we had to write the layout in a separate XML file and call dimensions, styles, etc. from another XML file. Now you can do everything just by using Kotlin.

  • Fully declarative for UI components means that you can simply describe what your UI should look like and on every application state change your UI gets updated automatically.

  • It is compatible with the old UI toolkit which gives you the possibility to mix both toolkits at the same time

  • Development is going to be more accelerate as it supports apply changes and live preview

  • Jetpack Compose is platform-independent and backward compatible with all Android versions

Let's write some code

" Note: Jetpack Compose is currently in Developer Preview. The API surface is not yet finalized, and should not be used in production apps."

To build an application that uses Jetpack Compose we have to use Composable functions that transform application data into a UI hierarchy. To create a composable function just add @Composable annotation which then tells Compose compiler that your function should be treated as a widget. Let's create a composable function that shows the “Hello World” text on the screen.

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Greeting("World") } }
} @Composable
fun Greeting(name: String) { Text(text = "Hello $name")
}

As you may have noticed there is no setContentView method which means that we don’t use XML layouts anymore. Method setContentView is replaced by the setContent method whose responsibility is to call composable functions.

Like I mentioned before, Android Studio 4.0 comes with a built-in live preview. To be able to run the live preview you have to add @Preview annotation before @Composable. Keep in mind that it is not possible to preview the function that takes parameters. That is the reason why I created a new function HelloWorldPreview which then calls our Greeting function. Once you make a change inside composable activity you will see Build & Refresh button appears at the top right corner. Click it and you will see the changes you have made inside the preview window.

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Greeting("World") } }
} @Composable
fun Greeting(name: String) { Text(text = "Hello $name")
} @Preview
@Composable
fun HelloWorldPreview(){ Greeting(name = "World")
}

One more cool thing about the live preview is that you can have multiple live previews. Just create one more composable function annotated with @Preview and another preview will be added to the preview window.

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Greeting("World") } }
} @Composable
fun Greeting(name: String) { Text(text = "Hello $name")
} @Preview("Preview 1")
@Composable
fun HelloWorldPreview(){ Greeting(name = "World")
} @Preview("Preview 2")
@Composable
fun HelloWorldPreview2(){ Greeting(name = "World")
}

Data flow

To avoid conflicts and showing inconsistent data Jetpack Compose relies on the SSOT (Single Source Of Truth) concept. There are two ways that data can flow. Top-down and Bottom-up data flow. Top-down data flow is done by passing parameters from the parent function to its children and is always in control of the data of its children. Bottom-up data flow happens when the children's composable function receives an event. That change should be passed from the bottom to the parent on top which then updates its children accordingly.

Data flow in Compose apps. Data flows down with parameters, events flow up with lambdas.

Let's take a look at the real example of the gist below.

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ManageTextFunction("Some text") { text -> Toast.makeText(this, "Clicked text: $text", Toast.LENGTH_LONG).show()} } }
} @Composable
fun ManageTextFunction(text: String, onSelected: (String) -> Unit){ ShowText(text = text, onClick = {onSelected(text)})
} @Composable
fun ShowText(text: String, onClick: () -> Unit){ Clickable(onClick = onClick) { Text(text = text) }
}

In the example above you can see that once the item is clicked the ShowText function passes that information back to the top of the hierarchy, using lambdas until it reaches the composable function that is responsible to handle that information. In this case, the setContent function is at the top and has to use passed information to update UI according to the click. That is how bottom-up data flow is done in a real example. When it comes to top-down data flow it is just about passing parameters to the child function at the bottom. Specifically, in this example, we pass String and lambda to the bottom of the hierarchy.

@Model annotation

One more thing that comes in handy when using Compose is that it reacts to every state change. All we have to do is to annotate our model class with @Model annotation and let Compose compiler do its magic. Compose compiler will then rewrite that class and make it thread-safe and observable.

Let's make a simple counter application that shows the power of state management using @Model annotation.

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MaterialTheme { Counter(CounterState()) } } }
} @Composable
fun Counter(state: CounterState) { Column { Button( text = "${state.count} clicks", onClick = { state.count++ } ) }
} @Model
class CounterState(var count: Int = 0)

In this example, we created a simple button that displays the number of clicks. As you can see ButtonCountState class is annotated with @Model annotation which will automatically make ManageButton function to recompose if data inside ButtonCountState model is changed. That way, we avoid calling the same function multiple times with different parameters to update its state.

Conclusion

There is still much room to improve on Jetpack Compose and the Android team is aware of that. They are constantly looking for feedback from users to make Jetpack Compose as best as possible. It is currently in developer preview; they plan to bring it to the beta next year and make it ready to use in production applications. Jetpack Compose is still in very early stages of development and some things are missing and some are getting changed, but it looks promising and that shouldn’t be a reason not to try playing with it.

Share this blog:

twitter logo
facebook logo
linkedin logo
link logo

Subscribe to our newsletter

We send bi-weekly blogs on design, technology and business topics.

Similar blogs

Job application illustration

You could use our expertise?

Let's work together.