JetpackCompose.app Dispatch Issue #4

💌 In today's issue, we discuss Compose UI previews on web, Airbnb's new screen architecture, XML in Compose 😵‍💫 & Power Asserts

Good Morning Friends! This is JetpackCompose.app’s Dispatch, rolling into your Wednesday as reliably as a build failing just before your demo 🙈.

This is Issue # 4 and we have a lot of interesting things to cover.

💡 Insider Insight

Let’s kick things off with a fun fact that might surprise you: the earliest prototypes of Jetpack Compose actually used a combination of Kotlin and XML syntax. You might be thinking, “Wait, hasn’t Android always mixed the two?” True, but what I’m talking about looked like this:

@Composable
fun Demo() {
     <Button onClick>
         <Padding padding=EdgeInsets(16.dp)>
             <Text text=TextSpan(text = "CUSTOM BUTTON!") />
         </Padding>
      </Button>
}

😵‍💫 Yeah, this mind-bending syntax was even available in the earliest public version of Compose. If you’re familiar with React, you’ll recognize the uncanny resemblance to JSX, where mixing HTML-like syntax with JavaScript is the norm.

So, why did the Jetpack Compose team decide to sunset this XML-like syntax and switch to the function-based syntax we all know and love?

In a dusty old thread from 2019, Romain Guy suggested that they realized the XML tags were essentially acting like function calls anyway. Plus, they saw a golden opportunity to simplify our lives by reducing the context switching between Kotlin for business logic and XML for UI descriptions.

Personally, I find these kinds of insights fascinating. There’s so much to learn from API design, especially when a lot of thought goes into it. And remember, decisions like these impact millions of Android developers, so it’s not just a casual coffee chat decision (though I bet a lot of coffee was involved).

😆 Dev Delight

🤔 Interesting tid-bits

  • Ever since Compose Multiplatform was first announced, I've dreamed of a future where you could write your Composable UI directly in the browser and instantly preview it live. Well, it looks like the brilliant folks at JetBrains are making that dream a reality! 🤩

    Even more impressively, they are adding this functionality to the Kotlin Online Playground. If you’d like to give it a spin, use this custom link. Fair warning: it’s super slow, but hey, it’s a start! Imagine the possibilities once it speeds up.

Compose Web integrated in the Kotlin Playground

  • A key feature that Kotlin 2.0 brings with it is Power Assert - a debugging feature that makes assertions more informative and easier to debug. Instead of a simple assertion failure message, Power Assert provides a detailed view of the failed expression, showing the values of all variables involved. Let’s look at an example to wrap your head around what I mean. Imagine this is one of your tests, and unfortunately, like a lot of your managers, it’s set up for failure (just kidding, I know each and every one of you is absolutely crushing it at work).

@Test
fun testFunction() {
    val hello = "Hello"
    val world = "world!"
    assert(
        hello.length == world.substring(1, 4).length
    ) { 
        "Incorrect length" 
    }
}

Now when this test fails, instead of a simple message that confirms it’s failure, it gives you this detailed visualization so that you can debug why it failed 🤯

More importantly, it works with the default assertion primitives like assert, require, check and assertTrue. If you’d like to use it, it just requires a couple lines of setup and voila!

// build.gradle
plugins {
    id 'org.jetbrains.kotlin.plugin.power-assert' version '2.0.0'
}

@OptIn(ExperimentalKotlinGradlePluginApi::class)
powerAssert {
    functions = [
        "kotlin.assert", 
        "kotlin.test.assertTrue", 
        "kotlin.test.assertEquals", 
        "kotlin.test.assertNull"
    ]
    includedSourceSets = [
        "commonMain", 
        "jvmMain", 
        "jsMain", 
        "nativeMain"
    ]
}

One thing worth noticing is how this framework is implemented as a compiler plugin, similar to Jetpack Compose itself. This should give us some clues about how it probably works - it most likely transforms the assertion primitives such as assert and passes extra metadata such that it has their values available at the time of printing the failure. This is a very creative way of leveraging the power of compiler plugins and one more reason why it should be in your toolbox.

💻 Code Corner

You might remember that in the previous issue, we spoke about the newly minted rememberGraphicsLayer API that allows one to capture a composable into a bitmap. Rob wanted to take it a step further and wondered how he could capture a composable without actually displaying it. 🤯

This is a common practice in the web ecosystem, known as “headless browsing”, which has various use cases like web scraping, automated testing, and more. So, this question is not just interesting but also highly practical.

Rob decided to go down the rabbit hole and found a creative solution involving the Presentation class. If you are familiar with this class, call your parents and let them know that you’ve put in 10,000 hours in your craft and that they should be proud of you. For the vast majority of the rest of us, this should be a good "Today I Learned" moment, and you should thank your stars that you discovered the Dispatch Newsletter 😉

🔦 Community Spotlight

In today’s Community Spotlight, I want to feature a project that made me think, “Huh, why didn’t I think of this?!”

Dryrun is a brilliantly simple tool that lets you run the sample project of any Android repository with just one command. Once installed, here's all it takes to run a GitHub-based Android project:

dryrun https://github.com/cesarferreira/android-helloworld

With Dryrun, you can run the project directly on your connected device. No more downloading zips, opening them in Android Studio, waiting for syncs, and then cleaning up those pesky zip files you don’t need anymore. It’s like the Marie Kondo of Android tools—sparking joy by decluttering your workflow.

I love tools that remove barriers to entry. We’ve all been there, procrastinating on trying out a project because of all the steps involved. That excuse is out the window as it’ll be a non-issue going forward.

🎥 Media Player

Some of you might know that I work at Airbnb and played a role in its adoption of Jetpack Compose. As you would expect, initiatives of this magnitude are always a team effort. I have the distinct honor of working alongside some truly impressive engineers, and they recently gave a talk about the new screen architecture called Trio that they developed to power entire screens and flows in Compose at Airbnb.

This architecture is built on top of a popular library called Mavericks, which Airbnb open-sourced. More importantly, Trio does a few interesting and novel things that are worth learning about. Trust me, you don't want to miss this video. Check it out—

If your prefer reading instead, there’s also a 3 part blog series that you may like-

👂 Let me hear it!

What’d you think of this email? Tap your choice below and lemme hear it 👇

If you found this useful, please share it on your company’s Android specific Slack channel and/or your Twitter account. Your feedback is invaluable, and it helps me know that my efforts are making a difference. Otherwise, it feels like I’m shouting into the void!

On that note, here’s hoping that your bugs are minor and your compilations are error free,

Reply

or to participate.