Dispatch Issue # 3

🛜 "Server" Composabes, new graphicsLayer API, first-party visibility tracking, and debouncing state updates
Vinay Gaba Profile Image
Vinay Gaba on June 03, 2024
Hero Image

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 insights

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 🍶

PRs to enable the new rememberGraphicsLayer API All the Pull Requests that went into enabling the new rememberGraphicsLayer API

😆 Dev Delight

Louis_CAD
Louis_CAD
@Louis_CAD
Twitter logo
FlowRow is definitely not used for the FlowRow documentation! 😁
Hero Image

🥂 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)
}

Update: Ben Trengrove pointed out that a better fix might be to ensure that this line still exists in your build.gradle file. This will ensure that source information is included in the Compose compiler, which is crucial for the Layout Inspector to function properly.

buildFeatures { compose = 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

  1. 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 -

  2. 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.

Isuru Rajapakse
Isuru Rajapakse
@IsuruKusumal
Twitter logo
I think the most underrated announcement of today's @kotlinconf was kotlinx.rpc. This should theoretically let you do react-style server components (or shall I say - Server Composables. Here's a quick preview of how that looks like
Hero Image
  1. 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.

Android Quick Guides Quick guides are a new type of documentation for Android developers

  1. 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.

    A usecase that would benefit from the ContextualFlowRow component ContextualFlowRow is useful for implementing a use-case like this where

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

    1. Should this have been the default behavior for flow components? 🤔 It seems logical to optimize from the get-go.
    2. 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 at Google) recommended it in one of his tweet.

Here’s some more light on what the context was when 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.

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.

Divider

If you found this useful and learnt something new, I would be immensely grateful if you could share it within your networks. Here’s a prefilled tweet that you can share 🙏🏻 It costs you nothing but makes me feel really amazing to see that you found it useful. Will genuinely make my day 🥺

Until next time, here’s hoping that your bugs are minor and your compilations are error free,

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.