JetpackCompose.app Dispatch Issue #3

šŸ’Œ In today's edition, we discuss Server Composabes, new graphicsLayer API, visibility tracking, and debouncing state updates

Good Morning Friends! This is JetpackCompose.appā€™s Dispatch, where we sort through important Android happenings like it's a clearance sale ā€“ only the best bargains for your brain.

This is Issue # 3 and we have a bunch of very interesting topics for you to dive into šŸ¤æ

šŸ’” Insider Insight

Remember those PR reviews where you schooled your peers on the lambda variant of the graphicsLayer API? You were the office hero, the Compose wizard, the one who brought performance enlightenment. Well, get ready to don your superhero cape again because thereā€™s a new kid on the block: the rememberGraphicsLayer API.

The shiny new rememberGraphicsLayer API returns a Graphic Layers object that you can redirect draw commands to. Itā€™s primarily designed for magical feats like converting a Composable to a Bitmap. This is incredibly useful for sharing screenshots for bug reports, sharing app content on social media, or simply impressing your friends.

val coroutineScope = rememberCoroutineScope()
val layer = rememberGraphicsLayer()
Box(
    modifier = Modifier
        .drawWithContent {
            // The GraphicsLayer object exposes a record 
            // function to capture the content in the
            // layer.
            layer.record {
                // draw the contents of the composable
                // into the graphics layer
                this@drawWithContent.drawContent()
            }
            // draw the graphics layer on the 
            // visible canvas
            drawLayer(graphicsLayer)
        }
        .clickable {
            coroutineScope.launch {
                val bitmap = layer.toImageBitmap()
                // do something with the newly 
               // acquired bitmap
            }
        }
        .background(Color.White)
) {
    Text(
        "Thank you for reading Dispatch!", 
        fontSize = 26.sp
    )
}

Look at that elegance! The new API is straightforward, requiring just a couple of lines of code to work its magic. But behind the scenes, the implementation was no small feat. Check out this intricate process at the framework level. Great APIs are like good butlersā€”they handle all the complexity so you can focus on the finer things in life šŸ¶

All the Pull Requests that went into enabling the new rememberGraphicsLayer API

šŸ˜† Dev Delight

 šŸ„‚ Tipsy Tip

In a previous edition, we mentioned that the Compose Compiler codebase moved to the Kotlin repo. This change brought a shiny new composeCompiler DSL that lets you configure various compiler options. Sounds great, right? Well, plot twist: this new DSL actually breaks Layout Inspector. šŸ™ˆ 

But fear not, fellow devs, because Chris Banes is here to save the day. He shared a quick fix: just add the following compile option, and youā€™ll be back in business. The DSL doesnā€™t include source information by default, which is crucial for the Layout Inspector to function properly.

  composeCompiler {
      includeSourceInformation.set(true)
  }

Hopefully, this tip spares you a world of pain. If youā€™ve tried using Kotlin 2.0, youā€™ve likely encountered this issue.

šŸ¤” Interesting tid-bits

  • Ever tried logging impressions of components or screens in your app when theyā€™re displayed to a user? If youā€™ve been down that rabbit hole, you know itā€™s like trying to catch the wind. I tackled this at Airbnb using the Modifier system, but having an out-of-the-box solution wouldā€™ve been a time-saver, given how common this functionality is. The reason itā€™s not a standard feature? Thereā€™s a ton of nuance in defining what counts as an ā€œimpression.ā€

    Enter Rebecca Franks, a Dev Rel Engineer at Google, whoā€™s swooping in to save the day with a proposal for a new ā€œVisibilityā€ Modifier. This nifty Modifier aims to track visibility changes of a Composable easily. Itā€™s still a proposal because, like any good superhero, it has its kryptonite: performance implications when used in lists. But hey, itā€™s currently the best way to track visibility, so I encourage you to check it out. And if youā€™ve got opinions, suggestions, or just want to say hi, give Rebecca your feedback directly. Letā€™s help shape this API -

  • At the recent KotlinConf, one announcement flew under the radar but could be a game-changer: kotlinx-rpc. Itā€™s a first-party Kotlin library for adding asynchronous Remote Procedure Call (RPC) services to your apps. At first glance, it might not sound all that thrilling. However, Isuru Rajapakse quickly highlighted its potential to create React-style server componentsā€”or ā€œServer Composables,ā€ if you will.

    Imagine moving your app's business logic to the server. Isuru crafted a Proof of Concept using Squareā€™s Molecule library to host Composables on the server, which then emit a StateFlow stream consumed by the client-side UI. This means you can use the same mental model for both UI and business logic while the logic lives on the server.

    Pretty exciting, right? If youā€™re as intrigued as I am, you can check out his Proof of Concept in this Pull Request.

  • Google is shaking up documentation with a fresh format called ā€œQuick Guides.ā€ These guides focus on very specific tasks you might want to accomplish, like ā€œanimating character-by-character the appearance of textā€ or ā€œstyling part of a text.ā€ Itā€™s like a cheat sheet but cooler and more practical.

    This new style is similar to some of my own projects like ā€œLearn Jetpack Compose By Exampleā€ and ā€œCompose Snippetsā€ so Iā€™m thrilled to see Google hopping on this trend. It makes learning more hands-on and less like deciphering an ancient manuscript.

    I highly recommend checking these Quick Guides out and giving them a solid bookmark. With any luck, Google will keep adding new ones frequently.

Quick guides are a new type of documentation for Android developers

  • One of the quirks of using Composables like FlowRow/Column is their lack of optimization for a large number of child elements. These traditional flow components render all items, regardless of their visibility, which can be a performance drag. To address this, Google introduced ContextualFlowRow and ContextualFlowColumn in the 1.7.0-beta01 release. These components smartly limit composition to only visible items within constraints like maxLines or maxWidth. This ensures your app runs smoother by reducing the number of items composed based on the current context and display parameters.

    But wait, thereā€™s more! These new components also allow for contextual decisions, such as implementing overflow behavior with a ā€œSee moreā€ button when the constraints are hit.

    ContextualFlowRow is useful for implementing a use-case like this where


    From an API perspective, here are a couple of thoughts:

    • Should this have been the default behavior for flow components? šŸ¤” It seems logical to optimize from the get-go.

    • Itā€™s curious that these components are in the compose.foundation package. They feel specific enough to belong in the compose.material package. While this is a minor nitpick, thereā€™s a concern that the foundation packages might get bloated over time.

šŸ’» Code Corner

Todayā€™s Code Corner shines a spotlight on a clever snippet shared by Pablisco. He shows us how to extend the MutableState interface to create custom behaviors. Specifically, he implemented a version of MutableState that debounces the state value if itā€™s updated within a specified debounceTime.

As with many things in programming, thereā€™s more than one way to achieve the same goal. Pablisco offers an alternative snippet that uses a custom SnapshotMutationPolicy to accomplish the same debouncing behavior. The main difference is that this approach uses the default mutableStateOf implementation with a custom mutation policy. Dive into the implementation and usage here:

Itā€™s a great reminder that in coding, flexibility is key. Whether you choose to extend MutableState or use a custom mutation policy, youā€™ve got options to tailor your state management to your needs.

šŸŽ„ Media Player

I want to share a fascinating video with yā€™all that Iā€™m confident you didnā€™t expect to see. While the video is primarily focused on JavaScript, the ideas itā€™s presenting are valid even for the Compose ecosystem. In fact, the reason I stumbled on this video is because Jim Sproch, whoā€™s one of the people to propose Jetpack Compose @ Google, recommended it in one of his tweet.

Hereā€™s some more light on why he brought up this video -

I worked on product infrastructure at Facebook, where we interfaced with countless product teams, many of which were using Dependency Injection (DI) and others were not. This is where the more meta conclusions/understanding formalized in my mind. Cross cutting concerns were the source of problems. It was a consistent experience that cross cutting concerns (and DI in particular) made it very difficult to understand the impacts of small targeted changes. They are very difficult to unwind and refactor because they bury the complex behaviors that become implicitly assumed. One of my coworkers on React.js did an absolutely fantastic talk on the subject, which does a fantastic job of distilling these same findings; he independently arrived at the same conclusions, the talk is amazing.

Jim Sproch

Here, Jim was talking about how heā€™s not a fan of Dependency Injection and even CompositionLocals because thatā€™s also an implicit way of doing dependency injection in some ways. The talk doesnā€™t directly address this, however, it does dole out some good advice around abstractions, surface area of the language, etc.

šŸ‘‚ Let me hear it!

Whatā€™d you think of this email? Tap your choice below and lemme hear it šŸ‘‡

On that note, hereā€™s hoping that your bugs are minor and your compilations are error free,

Reply

or to participate.