State of Compose 2023 results are in! Click here to learn more
Published on

🚀 Pragmatic strategies on Jetpack Compose migration

Authors

Happy Thursday! Alex here 👋

In today's tutorial we will be talking about migrating to Jetpack Compose without breaking the bank.

This is not going to be a guide on using APIs on how to do migrations, even though we will briefly touch about the APIs available. Instead, we will discuss in which parts of your app you should (or not) use Jetpack Compose. We will also go through a plan on how to be able to use Jetpack Compose to write new features start to finish.

Turn on airplane mode, sit back, relax and enjoy today's tutorial.

Why you should not rewrite your app in Jetpack Compose

Rewrites take time, and they tend to cost tons of money.

From a customer point of view the fact that your app uses Jetpack Compose or another UI framework does not change much. Your app will not magically become better because you use Jetpack Compose over Views. By rewriting your entire app in Jetpack Compose you will end up spending double the amount of time on existing features. This excludes new issues that might be introduced from migrating to a new UI framework.

Instead of focusing on rewriting any part of your code base that does not improve the customer experience, you can focus on improving your app and provide more features using Jetpack Compose.

The end goal and how to get there

The ultimate goal is to be able to write new features in Jetpack Compose. Unfortunately, this cannot happen straight from the start in a mature project.

There is a high chance that you have a design system in place. You might have many custom components (such as buttons and text) that you reuse in your screens built with Android Views. There is no point in rewriting any component in Compose just to be able to write new features.

Here is my recommended approach on how tackle this:

  • Introduce new design components as composables instead of Views
  • Convert your existing custom views and use them in Compose
  • Migrate your theme to Compose

Let's go through different actions you can take to introduce Jetpack Compose in your app gradually with the goal of being able to write full features in Jetpack Compose.

Consider introducing new components in Jetpack Compose instead of Views

Instead of creating a new custom Android View class when your designer gives you a new component to implement, consider using Jetpack Compose instead.

This has two main benefits:

  • composable functions take less boilerplate to use than creating new Android views.
  • consistent behavior across platforms.

Jetpack Compose is an external dependency to the project. Components should have the same behavior across platforms as opposed to Android Views that might have bugs or strange behaviors depending on OEM and Android version.

Key player here is the ComposeView which allows you to bind composables in your XML layouts:

<!-- in your layout.xml include a ComposeView-->
<androidx.compose.ui.platform.ComposeView
        android:id="@+id/view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

which you can bind in your activity/fragment:

val composeView = findViewById<ComposeView>(R.id.view)
composeView.setContent {
    FancyComposable()
}

Migrate your design system to Jetpack Compose gradually

If you have a lot of custom Views that work great, there is no much point in rewriting them as composables.

Instead you can convert them to composable functions and use them directly in Jetpack Compose.

Here is an example of how to convert your custom view to a composable using AndroidView():

@Composable
fun FancyComposable(){
    AndroidView(
        create = { context ->
            // create or inflate your custom View
            FancyView(context)
        }
    )
}

which you can use from any screen written in Jetpack Compose:

@Composable
fun MyScreen() {
    FancyComposable()
}

Thoughts on migrating your XML theme to Jetpack Compose

Theming in Jetpack Compose cannot be used with Android views and vice versa. There is the Accompanist Material Theme Adapter that allows you to reuse Material Theme based themes with Jetpack Compose.

There might be an awkward phase where you might have to maintain two versions of your theme until you fully migrate to Compose. It is still possible to extend the MaterialTheme in compose with custom attributes using CompositionLocals but I would encourage you to rethink and slim down your theme, especially if you have a lot of custom theme attributes in place.

A word about activities, fragments and navigation

There was once a time, where multiple Activities used to be a common way to navigate around an Android app. Then came fragments and the single activity architecture. Then the Jetpack Compose navigation library was introduced to make navigating using fragments easier.

Jetpack Compose has its own version of the navigation library, where you can use composables to navigate across screens.

The official Compose navigation library has received a lot of backlash by the Android community and a lot of third-party navigation libraries have been created since then.

My personal thoughts on mature projects would be to keep the existing navigation you have, or at least do not worry about migrating your navigation in the near future. Technically there is no much benefit for switching your navigation infrastructure as much as being able to replace your Android Views with Composable functions.


In this tutorial we saw how to use Jetpack Compose in your Android app without rewriting the entire app. We saw how to focus on improving your app by using Jetpack Compose instead of rewriting. We saw how to convert your existing custom views so that you can use them in your composable screens. We also covered concerns on migrating your theme and navigation to compose.