HomeLearnQuickstartUnboxing Jetpack Compose: Experience My First Compose App

Unboxing Jetpack Compose: Experience My First Compose App

Updated: Jul 30, 2021 |

Published: Jul 30, 2021

  • Kotlin
  • Android

By Mohit Sharma

Rate this article

#Introduction

#What is Jetpack Compose?

As per Google, Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs”.

In my words, it’s a revolutionary declarative way of creating (or should I say composing 😄) UI in Android using Kotlin. Until now, we created layouts using XML and never dared to create via code (except for custom views, no choice) due to its complexity, non-intuitiveness, and maintenance issues.

But now it’s different!

#What is Declarative UI?

You know, imperative is like how you do something, and declarative is more like what you do, or something.

Doesn’t that make sense? It didn’t to me as well in the first go 😄. In my opinion, imperative is more like an algorithm to perform any operation step by step, and declarative is the code that is built using the algorithm, more to do what works.

In Android, we normally create an XML of a layout and then update (sync) each element every time based on the input received, business rules using findViewById/Kotlin Semantics/View Binding/ Data Binding 😅.

But with Compose, we simply write a function that has both elements and rules, which is called whenever information gets updated. In short, a part of the UI is recreated every time without performance issues.

This philosophy or mindset will in turn help you write smaller (Single Responsibility principle) and reusable functions.

I’m not really sure, but out of the many awesome features, the ones I’ve loved most are:

  1. Faster release cycle: Bi-weekly, so now there is a real chance that if you get any issue with composing, it can be fixed soon. Hopefully!
  2. Interoperable: Similar to Kotlin, Compose is also interoperable with earlier UI design frameworks.
  3. Jetpack library and material component built-in support: Reduce developer efforts and time in building beautiful UI with fewer lines of code ❤️.
  4. Declarative UI: With a new way of building UI, we are now in harmony with all other major frontend development frameworks like SwiftUI, Flutter, and React Native, making it easier for the developer to use concepts/paradigms from other platforms.

#Current state

As of 29th July, the first stable version was released 1.0, meaning Compose is production-ready.

#Get Started with Compose

#For using Compose, we need to set up a few things:

  1. Kotlin v1.5.10 and above, so let’s update our dependency in the project-level build.gradle file.

    1plugins {
    2 id 'org.jetbrains.kotlin:android' version '1.5.10'
    3}
  2. Minimum API level 21

    1android {
    2 defaultConfig {
    3 ...
    4 minSdkVersion 21
    5 }
    6}
  3. Enable Compose

    1 android {
    2
    3 defaultConfig {
    4 ...
    5 minSdkVersion 21
    6 }
    7
    8 buildFeatures {
    9 // Enables Jetpack Compose for this module
    10 compose true
    11 }
    12 }
  4. Others like min Java or Kotlin compiler and compose compiler

    1 android {
    2 defaultConfig {
    3 ...
    4 minSdkVersion 21
    5 }
    6
    7 buildFeatures {
    8 // Enables Jetpack Compose for this module
    9 compose true
    10 }
    11 ...
    12
    13 // Set both the Java and Kotlin compilers to target Java 8.
    14 compileOptions {
    15 sourceCompatibility JavaVersion.VERSION_1_8
    16 targetCompatibility JavaVersion.VERSION_1_8
    17 }
    18 kotlinOptions {
    19 jvmTarget = "1.8"
    20 }
    21
    22 composeOptions {
    23 kotlinCompilerExtensionVersion '1.0.0'
    24 }
    25 }
  5. At last compose dependency for build UI

    1 dependencies {
    2
    3 implementation 'androidx.compose.ui:ui:1.0.0'
    4 // Tooling support (Previews, etc.)
    5 implementation 'androidx.compose.ui:ui-tooling:1.0.0'
    6 // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
    7 implementation 'androidx.compose.foundation:foundation:1.0.0'
    8 // Material Design
    9 implementation 'androidx.compose.material:material:1.0.0'
    10 // Material design icons
    11 implementation 'androidx.compose.material:material-icons-core:1.0.0'
    12 implementation 'androidx.compose.material:material-icons-extended:1.0.0'
    13 // Integration with activities
    14 implementation 'androidx.activity:activity-compose:1.3.0'
    15 // Integration with ViewModels
    16 implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
    17 // Integration with observables
    18 implementation 'androidx.compose.runtime:runtime-livedata:1.0.0'
    19
    20 }

#Mindset

While composing UI, you need to unlearn various types of layouts and remember just one thing: Everything is a composition of rows and columns.

https://cdn-images-1.medium.com/max/2108/1*VhWkcj7aUWNdE7e3CYJdQw.png

But what about ConstraintLayout, which makes life so easy and is very useful for building complex UI? We can still use it ❤️, but in a little different way.

#First Compose Project — Tweet Details Screen

For our learning curve experience, I decided to re-create this screen in Compose.

https://cdn-images-1.medium.com/max/2000/1*yeFRhDs5R1CP4zaEomCmjQ.png

So let’s get started.

Create a new project with Compose project as a template and open MainActivity.

If you don’t see the Compose project, then update Android Studio to the latest version.

1 class MainActivity : ComponentActivity() {
2
3 override fun onCreate(savedInstanceState: Bundle?) {
4 super.onCreate(savedInstanceState)
5 setContent {
6 ComposeTweetTheme {
7
8 ....
9 }
10 }
11 }
12 }

Now to add a view to the UI, we need to create a function with @Composable annotation, which makes it a Compose function.

Creating our first layout of the view, toolbar

1 @Composable
2 fun getAppTopBar() {
3 TopAppBar(
4 title = {
5 Text(text = stringResource(id = R.string.app_name))
6 },
7 elevation = 0.*dp
8 )
9 }

To preview the UI rendered in Android Studio, we can use @Preview annotation.

https://cdn-images-1.medium.com/max/4856/1*ukkhEHOGJ2B7WlPpDxHHzg.png

TopAppBar is an inbuilt material component for adding a topbar to our application.

Let’s create a little more complex view, user profile view

https://cdn-images-1.medium.com/max/2000/1*EgdJyqYqrpsl2w67GSrHIw.png

As discussed earlier, in Compose, we have only rows and columns, so let’s break our UI 👇, where the red border represents columns and green is rows, and complete UI as a row in the screen.

https://cdn-images-1.medium.com/max/2000/1*ICvhTxCdsy8RXR8jsMfO3g.png

So let’s create our compose function for user profile view with our root row.

https://cdn-images-1.medium.com/max/3984/1*v-SIoDDh9pQSTtJ6ooSyqQ.png

You will notice the modifier argument in the Row function. This is the Compose way of adding formatting to the elements, which is uniform across all the elements.

Creating a round imageview is very simple now. No need for any library or XML drawable as an overlay.

1Image(
2 painter = painterResource(id = R.drawable.ic_profile),
3 contentDescription = "Profile Image",
4 modifier = Modifier
5 .size(36.dp)
6 .clip(CircleShape)
7 .border(1.dp, Color.Transparent, CircleShape),
8 contentScale = ContentScale.Crop
9 )

Again we have a modifier for updating our Image (AKA ImageView) with clip to make it rounded and contentScale to scale the image.

Similarly, adding a label will be a piece of cake now.

1 Text (text = userName, fontSize = 20.sp)

Now let’s put it all together in rows and columns to complete the view.

1@Composable
2fun userProfileView(userName: String, userHandle: String) {
3 Row(
4 modifier = Modifier
5 .fillMaxWidth()
6 .wrapContentHeight()
7 .padding(all = 12.dp),
8 verticalAlignment = Alignment.CenterVertically
9 ) {
10 Image(
11 painter = painterResource(id = R.drawable.ic_profile),
12 contentDescription = "Profile Image",
13 modifier = Modifier
14 .size(36.dp)
15 .clip(CircleShape)
16 .border(1.dp, Color.Transparent, CircleShape),
17 contentScale = ContentScale.Crop
18 )
19 Column(
20 modifier = Modifier
21 .padding(start = 12.dp)
22 ) {
23 Text(text = userName, fontSize = 20.sp, fontWeight = FontWeight.Bold)
24 Text(text = userHandle, fontSize = 14.sp)
25 }
26 }
27}

Another great example is to create a Text Label with two styles. We know that traditionally doing that is very painful.

Let’s see the Compose way of doing it.

1Text(
2 text = buildAnnotatedString {
3 withStyle(style = SpanStyle(fontWeight = FontWeight.ExtraBold)) {
4 append("3")
5 }
6 append(" ")
7 withStyle(style = SpanStyle(fontWeight = FontWeight.Normal)) {
8
9 append(stringResource(id = R.string.retweets))
10 }
11 },
12 modifier = Modifier.padding(end = 8.dp)
13 )

https://cdn-images-1.medium.com/max/2008/1*Sam96dWBFuNELaztMUAf0g.png

That’s it!! I hope you’ve seen the ease of use and benefit of using Compose for building UI.

https://cdn-images-1.medium.com/max/2000/1*eLrryz9etGCak2M3YPi1Ww.png

Just remember everything in Compose is rows and columns, and the order of attributes matters. You can check out my Github repo complete example which also demonstrates the rendering of data using viewModel.

If you have questions, please head to our developer community website where the MongoDB engineers and the MongoDB community will help you build your next big idea with MongoDB.

Rate this article
MongoDB Icon
  • Developer Hub
  • Documentation
  • University
  • Community Forums

© MongoDB, Inc.