Jetpack Compose Migration: Part 1. Get Started

Engine Bai
6 min readJan 13, 2022

--

Jetpack Compose has been one of the most discussed topics since it released the 1.0 stable version. It is expected to solve most of the problems with the current Android UI toolkit, which contains lots of legacies.

Let’s take a closer look at this new UI toolkits, there will be a series of migrations for our movie app — MovieHunt from Android XML (and Epoxy) to Jetpack Compose:

  • Part 1. Introduction + Detail screen migration
  • Part 2. Vertical list migration (with paging 3)
  • Part 3. Home (horizontal + vertical) migration (with paging 3)

What’s Jetpack Compose?

In a nutshell, Compose is a declarative UI toolkit developed entirely in Kotlin. (We will explain what declarative is later) Compose looks quite similar to existing UI frameworks like Flutter. The current Android UI framework had gotten more complex with legacies, Jetpack Compose aims to start fresh and be fully compatible with the current existing Android view system and accelerate our app development.

What’s the difference?

For the traditional Android world, we have to write XML for our UI components and layout, we specify the ID, apparences, styles, positions…etc in XML.

Layout in XML

And then use findViewById() in your Kotlin code to locate the UI components and then update the states:

In the Jetpack Compose world, we can write everything in Kotlin, from UI components to most of the properties, such as style/shape/color…etc. and provide the proper states for the UI to display. No longer are some written in Kotlin, some in XML.

Layout in Compose

Benefits and Core Principles

  • Idiomatic Kotlin: We can write very concise Kotlin code for our UI which gives us more delightful development experiences, we don’t have to switch between Kotlin and XML anymore.
  • Compatible with existing UI hierarchies: it a progressive UI toolkit that could be incrementally adoptable.
  • Write less code: We have to write lots of code either in XML and/or Kotlin for existing UI toolkits, especially for RecyclerView (you have to define a view holder and adapter, that is complex). Compose aims to simplify and accelerate the app development.
  • Single source of truth: Our UI changes are driven from model only, that makes it much less buggy and easy to trace code or debug.
  • Declarative UI: This new paradigms that give us the advantages of functional programming, such as more predictable and easy to test (given the same input, always returns the same output), no side-effects (eliminating the shared states), immutability (your data flow is lossy without it).
  • Composing UI with several composable functions: We can build a complex UI by composing of small and reusable components which are called composable functions.

Shifting from Imperative to Declarative

As you can see above, in the old way we have to find the UI component via findViewById(R.id.xxx) and mutate the UI state, this is called imperative, we describe how to do by giving the sequences of commands that performs some actions to change the state.

In contrast, you just specify what are the UI components (inside the @Composable function or by composing @Composable functions) and what are the values to display (by providing function parameter values) in Compose world, and the framework will render the UI for you, you don’t have to mutate the UI state anymore, this is declarative UI that describes what to do without specifying the detail, not how to do, you only need to specify what your current state should be.

f(state) = UI

For the declarative UI, we builds our UI to reflect the current state (model) of the app, that is, we drive UI from the state, and we change the state and it will trigger UI rebuild from the new state, we won’t mutates the UI itself any more, the state serves as the single source of truth.

Hands-on Practice

Let’s start to migrate XML to a composable function. (We skip the setup steps, which you can follow the instructions from developer document) This part we’re going to use movie info in the movie detail screen as example, here we go.

MovieInfo in Detail screen.

As you can see from the screen, there is image, name, rating…etc., we will define those fields as composable function parameter:

We will start with uppercase letters for composable functions.

We arrange the UI components in a vertical LinearLayout in XML, and for composable world, the equivalent component is Column() / Row() which represents vertical / horizontal LinearLayout respectively, here we use Column() with several Text() to arrange the components inside the composable MovieInfoWidget() function:

Jetpack Compose also provides preview annotation so that we can see what our composable function looks like in Android Studio, all we have to do is define another composable function with @Preview annotation, and return the composable function of our UI with parameter values:

After defining the preview composable function and building the project, you can see the UI preview in Android Studio, and for now, it looks too simple without any style applied. Next step we will define and apply the style / theme for our beautiful UI design.

UI components without any styles/themes

We’re going to migrate colors.xml, styles.xml and dimens.xml to Kotlin code, you can take a look at this post that provides very comprehensive instructions regarding the style/theme in Jetpack Compose, we will skip this part here and show the code after applying the style/theme.

The preview looks much better and closer to our desired UI.

What we added are not only the styles, we also added the `modifier`, the modifier in Jetpack Compose can set the appearance or decorate your UI components, such as size, color, padding…etc., you can take a glance at the document to know all the attributes that we can set for our UI.

There is one composable function we just used before but didn’t mention yet: MovieRatingWidget(), there are three components laid in horizontally LinearLayout that we can use Row in Jetpack Compose. Row will place the components horizontally.

Last part we will add a back button to top-left side overlap the image, here we can use Box() for UI component overlap:

So the final code is here:

In this part, we’re talking about the basic compose functions: Text(), Button(), Column(), Row(), Box() …etc to build our UI, modifier and style for UI decoration. For the combination of Column(), Row(), and Box() with the powerful modifier, you could build a more elaborate layout for your app.

For full project feel free to clone or contribute and it would be nice to star my project, thank you for your support!

--

--

Engine Bai

白昌永 (大白) Software Engineer, Athlete, Learner. Focused on Mobile / Backend / AI + ML