Dispatch Issue # 1: Inagural Edition šŸš€

šŸš€ Code structure optimizations, Android memes, New Shared Element Transition APIs, Debugging Compose State & More!
Vinay Gaba Profile Image
Vinay Gaba on May 09, 2024
Hero Image

Good Morning Friend! Welcome to the very first edition of JetpackCompose.appā€™s Dispatch šŸ’Œ Think of us as your Android barista ā€“ we know your order, and yes, we add the extra shot of clarity.

šŸŽ© Insider Insight

Todayā€™s Insider Insight is about how the structure of your Jetpack Compose code can impact your appā€™s performance. Consider this example, where we aim to implement a series of bars made up of multiple colored dots.

Individual Composables Visualization A bar visualization that we want to implement in Jetpack Compose

Initially, developers might opt to create a Composable function for each individual dot, leading to a straightforward but performance-costly implementation:

@Composable
fun Visualization(bars: ImmutableList<Bar>) {
    Row {
        bars.forEach {
            Bar(it)
        }
    }
}

@Composable
fun Bar(bar: Bar) {
    ....
    Column {
        for(i in 0..numBarRows) {
            Row {
                for (i in 0..4) {
                    Dot(...)
                }
            }
        }
    }
}

@Composable
fun Dot(color: Color) {
    Box(...) {...}
}

This approach is intuitive and readable, yet it results in approximately 350 Composable functions that the framework needs to manage, significantly increasing the workload across all phases of the composable lifecycle: composition, layout, and drawing.

An alternative strategy is to draw all dots in a bar directly on the Canvas using a single Bar Composable.

Aggregated Composables Visualization In this approach, each bar represented by the yellow border is responsible for drawing all the dots within it directly on the Canvas

@Composable
fun Visualization(bars: ImmutableList<Bar>) {
    Row {
        bars.forEach {
            Bar(it)
        }
    }
}

@Composable
fun Bar(bar: Bar) {
    Canvas() {
        for (i in 0 until bar.numRows) {
            for (j in 0 until bar.numColumns) {
                drawCircle(....)
            }
        }
    }
}

This method drastically reduces the number of Composables, significantly decreasing resource use during the critical phases:

  1. Composition: Fewer Composables streamline setup and management.
  2. Layout: A simplified layout phase cuts down computation time.
  3. Drawing: Fewer Composables mean faster rendering, as the system can batch draw calls more efficiently.

This optimization by consolidating multiple elements into fewer Composables can significantly enhance performance and user experience. As you design your Compose layouts, consider the benefits of grouping UI elements strategically.

Trade-offs: This isnā€™t a silver bullet. Always weigh the benefits against the potential drawbacks. In scenarios where the performance gain is substantial, like our example, adopting a more complex but efficient method is advantageous. However, if the performance improvement is marginal, prioritizing code readability and ease of implementation might be more beneficial.

Hat-tip to my friend and colleague Felipe Roriz who first brought this up during a conversation and got to the bottom of it.

šŸ˜† Dev Delight

Modifier Imports Weā€™ve all been frustrated by this. Thankfully, you can avoid this by following the steps from this article that I wrote a couple years ago.

Thinking about Java WHY!!!
Source

šŸ¤” Interesting tid-bits

  1. After a few false starts and nearly two years since the Compose 1.0 release, shared element transitions have finally landed in Compose with the 1.7.0-alpha07+ release šŸ„³ Last week, Google published a guide showcasing these APIs, and they are absolutely BEAUTIFUL šŸ˜. The animation APIs in Compose have set a new standard, significantly enhancing user experience over the traditional view system. This new functionality adds yet another layer of easy-to-use, eye-catching transitions, marking a leap forward for the Compose story.
  2. Last week, the Jetpack Compose compiler codebase packed its bags and moved into the Kotlin repo. This intriguing move has positive implications for us developers. No more wrangling with compatibility maps to find which Kotlin version pairs with the Compose compilerā€”hallelujah! šŸ„³ From Kotlin 2.0 onward, Compose and Kotlin will release together, sharing the same version number. So, the Compose Compiler is jumping to 2.0 to catch up. A couple of other nifty changes come along for the ride: Maven coordinates are now org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable, and no more fiddling with kotlinCompilerExtensionVersionā€”thank you, universe! Here's a handy Pull Request showing just how seamless this switch will be in practice.
  3. The Google Drive team published a case study about how they rewrote their home screen in Jetpack Compose and completed it in half the estimated time. The Compose version required 57% less feature code and 76% less test code while adding net new features and meaningfully increasing test coverage. Now that's what I call doing more with less! Someone promote the entire team already šŸ˜‚Ā The interesting bit here is how a planned redesign is the perfect excuse to hop on the Compose train. It's a tried-and-true strategy among hundreds of companies over the past few years, ensuring they don't make enemies out of their feature developers with dreaded forced migrations. Why force it when you can glide right into something better?

šŸ’» Code Corner

Have you ever wondered why your Composable is recomposing due to a state read? Sometimes itā€™s hard to tell even if you are using the Recomposition count tracker thatā€™s embedded into the Layout Inspector in Android Studio. Well you donā€™t need to guess anymore because Andrei Shikov has you covered. His snippet of code makes it easy for you to know the exact state thatā€™s causing recompositions from the logs that it emits. Itā€™s super easy for you to use as well -

// Just wrap the composable that you need more
// information about with the following Composable

DebugStateObservation("MyCustomComposable") {
    MyCustomComposable(...)
}

Thatā€™s all the setup that it needs! Check it out -

šŸ”¦ Community Spotlight

In today's community spotlight, we're shining a light on a couple of projects that have boldly stepped into the void left open in the Compose ecosystem: Markdown rendering! These projects are more relevant than ever in today's chat-first era, where LLMs churn out Markdown-rich text like it's going out of style. Formatting and parsing their output is crucial for many apps these days, making these projects absolute gems.

  1. MarkdownTwain
  2. compose-markdown

The community has been clamoring for a native solution, as seen in this issue, where 115 folks have enthusiastically thrown in their +1s. The good news is that the change landed last month, meaning Markdown rendering will soon be natively supported in Compose šŸ„³. But hey, if Google builds in the functionality you created a library for, you get to wear that badge of honor as a maintainerā€”consider it a compliment!

Welcome to the VIP club
To read the rest of the post, subscribe and never miss an issue!
Already a subscriber? Use the same email id to login again.