Introduction to Jetpack Compose

Khushboo Aggarwal
4 min readAug 17, 2021

“Design is everywhere. From the dress you’re wearing to the smartphone you’re holding, it’s design.”

A beautiful design catches attention and a smooth experience makes your app more user friendly. So, the expectations around UI development have grown enormously. Today, users expect a polished smooth interface having animations and motions along with the technical functionalities, the app provides. So to ease out the process of delivering an easy encounter, Jetpack Compose has come in action. Jetpack Compose is the modern toolkit for building native Android UI.

For this article, its not necessary to be familiar with View based approach first(though surely will be helpful), you can directly start with Compose.

Compose Model

So lets start with how Compose declarative approach is different from View based approach. Earlier, an Android view hierarchy has been represented as a tree of UI widgets and as the state of the app changes because of things like user interactions, the UI hierarchy needs to be updated to display the current data. We use functions like findViewById(), and change nodes by calling methods on the widgets which change the internal state of the widget.

Manipulating views manually increases the chance of errors. If a piece of data is rendered in multiple places, it’s easy to forget to update one of the views that shows it. It’s also easy to create illegal states, when two updates conflict in an unexpected way. In general, the software maintenance complexity grows with the number of views that require updating.

So, we need a declarative UI model that conceptually regenerates the whole UI from scratch then apply necessary changes. But one challenge with regenerating the entire screen is that it is potentially expensive, in terms of time, computing power, and battery usage. To reduce this cost, Compose intelligently chooses which parts of the UI need to be redrawn at any given time. This process of re-running the composable again with the new data is known as Recomposition.

Simple Composable Function

Using Compose, you can build your user interface by defining a set of composable functions that take in data and emit UI elements. So enough of theory for now, lets jump to some coding part. A simple composable function will look something like this -

@Composable
fun Greeting(name: String) {
Text(text = name)
}

Let’s discuss the anatomy of this composable function.

  • The function is annotated with the @Composable annotation which informs the compiler that this function is intended to convert data into UI, and hence is a composable function. Also the function doesn’t return anything, they just describe the state of the UI.
  • Composable functions can accept parameters, In this case it receives name as parameter of type String. Ideally this data is immutable that the composable function doesn’t change, rather it should be a transform function for that data.
  • The function displays text in the UI. It does so by calling the Text() composable function, which actually creates the text UI element. Composable functions emit UI hierarchy by calling other composable functions and the sequence in which they are written don’t matter. They can run in any order parallely.

We are able to use all of the language level primitives that Kotlin has to do the things dynamically like we can use control flow statements, loops to handle more complex logic. Also, Compose provides the Compose’s standard layout elements and a large variety of composables based on Material Design.

Lifecycle of Composables

When Jetpack Compose runs your composables for the first time, during initial composition, it will keep track of the composables that you call to describe your screen state. Then, when the state of your app changes, Jetpack Compose schedules a recomposition.

A Composition can only be produced by an initial composition and updated by recomposition. The only way to modify a Composition is through recomposition.

The lifecycle of a composable is defined by the following events: entering the Composition, getting recomposed 0 or more times, and leaving the Composition.

Recomposition is typically triggered by a change to a State<T> object. If a composable is called multiple times, multiple instances are placed in the Composition. Each call has its own lifecycle in the Composition. For Example,

@Composable
fun Greeting() {
Column {
Text("Hello")
Text("World")
}
}

In this, both the Text objects will have a separate instance and their own lifecycle independently.

Managing State in Compose

State is basically anything that depicts the current content to be shown which can be changed over time like a listing of posts, showing placeholder for empty data etc.

Compose is declarative and as such the only way to update it is by calling the same composable with new arguments(recomposition). These arguments depict the UI state and any time a state is updated a recomposition takes place. For example, like in xml an edit text don’t automatically update, composables have to be told explicitly that the state has changed to update accordingly.

@Composable
fun InputField() {
OutlinedTextField(
value = "",
onValueChange = { },
label = { Text("Name") }
)
}

If you run this, you’ll see that value will not get updated in the field that’s because you will explicitly have to update the value. Lets see how

@Composable
fun InputField() {
var text by remember{ mutableStateOf("")}
OutlinedTextField(
value = text,
onValueChange = { text = it},
label = { Text("Name") }
)
}

We’ll see what var text by remember{ mutableStateOf("")} does in our next article. For now, run it and you’ll see the text will update as you type.

So, this article gives a brief overview of Jetpack compose, next we will discuss on how to build Layouts, App Theming and States in Compose.

--

--