JetpackCompose.app's Dispatch Issue #16

šŸ’Œ In today’s Dispatch: šŸ—‘ļø Google Play’s 47 % app-purge drama, šŸ› ļø Amazon’s shiny new KMP ā€œApp Platformā€, šŸŽžļø ADB slow-mo frame-timing captures, šŸŽØ the theme bug that steals your Column’s color, 🤣 "Soft Earnings" and šŸ“Š @Preview-free code-coverage magic.

Your mobile release ā€œtaxā€ costs more than you realize.

Join mobile leaders from Skyscanner and SoFi on May 22 to measure exactly what you’re losing—and learn the real ROI of improving your mobile release process.

GM Friends. This is JetpackCompose.app’s Dispatch, sliding into your inbox with the grace of a Compose recomposition that actually skips unnecessary work.

This is Issue # 16 and is jam-packed with practical tips, juicy industry tidbits, and a healthy dose of nerdy enthusiasm. Let’s dig in!

šŸ•µšŸ»ā€ā™‚ļø Insider Insight

Let’s be honest: debugging animation jank is right up there with ā€œherding catsā€ and ā€œexplaining state hoisting to your managerā€ on the frustration scale. But here’s a tool that flies under the radar for even seasoned Android devs: ADB’s --bugreport option for video recordings. Simply run the following:

adb shell screenrecord --bugreport /sdcard/recording.mp4

You’ll get a video recording of your app with frame-timing overlays baked in—like frame numbers, timestamps, and dropped frame indicators. It’s like having a personal slow-mo referee for your app’s UI performance!

Why does this matter?

  • Diagnose Animation Hiccups: See exactly where frames are being dropped or delayed during those tricky transitions or complex Compose animations that you are now able to build with the wonderful APIs it offers.

  • Share with Team: Got a performance bug that only happens on your coworker’s 5-year-old Samsung? Now you can record, annotate, and send evidence for all to see (and fix!).

  • When to Use: Anytime you optimize animations, debug ā€œjank,ā€ or want to impress your PM with a CSI-style breakdown of why that modal takes 500ms too long to appear.

Despite our best efforts, sometimes issues slip through the cracks. That's why having an amazing observability tool in your corner is important to keep your app humming. Bitdrift gives you on-demand observability that's custom-built for mobile teams: no log limits, no overage fees, and no waiting on your next app release. Learn More

When this code is run, the Column doesn’t render the background color that was applied to it. Why is that?

@Composable
fun MainScreen(
    modifier: Modifier = Modifier,
    nightModeEnabled: Boolean = false
) {
    val screenModifier = modifier
        .background(color = AppColors.background)
        .fillMaxSize()

    AppTheme(darkMode = nightModeEnabled) {
        Column(modifier = screenModifier) {
            // Your content here
        }
    }
}

šŸ˜† Dev Delight

The next time you want to convince the hiring manager to skip some rounds, send them this screenshot šŸ˜Ž

šŸ™‹šŸ»ā€ā™‚ļø How do I?

Today’s question: How do I exclude Composable Previews from Code Coverage Reports

Raise your hand if you’ve ever looked at your code coverage report and thought, ā€œHow do I have 800 lines of untested code in my UI module?ā€ Only to realize—yep, it’s all those @Preview functions littering your Compose files. šŸ˜…

The solution depends on the framework you are using to calculate the code coverage.

If you are using Kover:

You can configure Kover to ignore anything under a specific annotation, e.g. @Preview. It looks along the lines of —

configure<KoverReportExtension> {
    filters {
         excludes {
             ...
             annotatedBy(
                 "androidx.compose.ui.tooling.preview.Preview"
             )
         }
     }
} 

Easy peasy šŸ¤“

If you are using Jacoco:

Unfortunately, Jacoco can’t directly filter by arbitrary annotation. However, here’s a secret 🤫 - it will ignore anything annotated with ā€œGeneratedā€.

This is shaky grounds if I’m being honest since this is not an API contract and just an implementation detail, however, that hasn’t stopped manny teams from creating custom annotations that end with the suffix ā€œGeneratedā€ and then adding it to their previews. As an example, annotating your previews with this custom annotation will be skipped by Jacoco from the code coverage reports.

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class ExcludeFromCodeCoverageReport

Then simply annotate your previews:

@Preview
@ExcludeFromCodeCoverageReport
fun MyComponentPreview() { ... }

Pro move: Write a small script or use a Kotlin compiler plugin to auto-insert the exclusion annotation on all your preview functions. Some teams have hundreds (if not thousands) such annotations—automation will save your sanity.

šŸ¤” Interesting tid-bits

The Great Google Play Purge: 47% Fewer Apps, 100% More Drama

Ever opened the Play Store lately and thought, ā€œHuh, didn’t there used to be more… stuff?ā€ You’re not hallucinating (at least not about this): Google Play has shed a jaw-dropping 47% of its apps since early 2024. That’s a drop from 3.4 million to about 1.8 million apps worldwide!

What’s behind this mass extinction event? Google’s been on a crusade to oust low-quality, spammy, and downright useless apps. The new policies aren’t just targeting broken apps anymore—they’re also eliminating so-called ā€œstaticā€ apps (think single-wallpaper wonders, glorified PDFs, or those apps that do, well… nothing).

But there’s more: stricter verification requirements, expanded human reviews (no more sneaking in a ā€œHello Worldā€ bitcoin miner at 3am), and a heavy investment in AI-driven threat detection. In 2024 alone, Google claims it blocked 2.36 million policy-violating apps and banned over 158,000 developer accounts. Yikes.

Why should you care?

  • Visibility boost: With less junk, high-quality apps (like yours, obviously) have a better chance to shine.

  • Publishing pains: The flip side is that even legitimate apps are running into more hoops—extra verifications, tougher quality checks, and the occasional Kafkaesque review cycle.

  • Not an industry-wide trend: Apple’s App Store actually saw a slight increase in total apps during the same period, so this is uniquely Android’s growing pain.

My take:
This is (mostly) a good thing for users and serious devs. But let’s be real—the process has been bumpy, especially for indie and small-team developers. Expect the rough edges to smooth out as Google iterates and developer tooling catches up. I’m going to be at Google I/O next week and I plan to surface this directly to the fine folks at Google and get their perspective on things. Stay tuned for the next issue which is going to give you a behind the scenes look at Google I/O 2025!

šŸ¾ Code Corner

Amazon’s ā€œApp Platformā€: A New Contender for Multiplatform Architecture (and Why You Should Care)

It’s not every day that Amazon open-sources a new application framework, especially one targeting Kotlin Multiplatform. Enter App Platform—a lightweight, opinionated framework for state and memory management across Android, iOS, JVM, and (soon) Web. Let’s break down what makes it worth a look, especially if you’re architecting for scale or dreaming of true code reuse.

Key Features

  • Strict Separation of Concerns: App Platform enforces a clean split between APIs and implementations. This not only keeps your boundaries crisp (no more ā€œleaky abstractionsā€ horror stories) but can also reduce build times. The framework even validates your module structure at build time!

  • Integrated Dependency Injection: By default, it uses kotlin-inject-anvil (but you can swap it out). You get the flexibility of Dagger/Anvil, but it’s not hard-wired—use what fits your stack. Fun fact: This project is being led by Ralf Wondratschek who happens to be the creator of Anvil.

  • Scopes as First-Class Citizens: App Platform makes ā€œscopeā€ a fundamental concept. You get clear, lifecycle-aware boundaries for features—think ā€œscreen,ā€ ā€œsession,ā€ or ā€œapplicationā€ scopes, each with their own DI, coroutine scopes, and teardown hooks.

  • Presenter Pattern, Powered by Molecule: Business and navigation logic is written using Compose (via Molecule), making reactive state management more natural than wrangling flows and callbacks.

  • UI Layer Decoupling: The UI is ā€œpluggable.ā€ Want Compose on Android, SwiftUI on iOS, or a mix of both? The renderer pattern isolates UI, so you can swap or test easily.

  • Testing First: Tons of helpers and fakes for unit/device testing. Bonus: thanks to Compose Multiplatform, you can even test renderers in isolation on iOS and desktop.

  • Gradle Plugin Magic: The setup DSL configures the Compose compiler, KSP, DI integrations, and even Android namespaces/artifact IDs for you. Less yak-shaving, more coding.

Overall, I think this is pretty interesting to see given that it’s targeting Kotlin Multiplatform and it’s always nice to have a big player backing an emerging framework. Still early days but I think it’s a big vote of confidence from them and will help codebases scale better.

Why doesn’t the Column get the correct background?

Answer

Well, it’s because it accesses the theme before you set it, so it gets the default colors instead of the ones you want. Be very careful with storing modifiers in variables and applying them later, it's very easy to mistakenly use them multiple times and/or cause bugs that aren’t obvious.

Here’s what you can do instead:

@Composable
fun MainScreen(
    modifier: Modifier = Modifier,
    nightModeEnabled: Boolean = false
) {
    AppTheme(darkMode = nightModeEnabled) {
        Column(
            modifier = modifier
                // Here, the background color is accessed
                // only in the scope of the AppTheme
                .background(color = AppColors.background)
                .fillMaxSize()
        ) {
            // Your content here
        }
    }
}

šŸ‘‚ Make your voice heard

Have opinions about Android Development/Jetpack Compose and want to share it directly with the folks working on it?

Well, you are in luck because the Android team is running a User Research Study focusing on Android Studio Tooling and they want to hear from you. They are especially interested in feedback about UI development and animations in Compose.

It’ll be a 75 min session and they are offering up-to $300 in gift code for your time.

This isn’t an ad - I just thought that this audience is packed with seasoned leaders so I’ll surface this for everyone to be aware of. You can sign up here.

šŸ¦„ How you can help?

If you enjoy reading this newsletter and would like to keep Dispatch free, here are two quick ways to help:

šŸ‘‰šŸ» Chip in via Github Sponsors. If your company offers an education budget, contributing a ā€œcoffeeā€ to keep this newsletter going will certainly qualify. You’ll get an instant receipt for reimbursement, and I’ll keep Dispatch running ā˜•ļø

šŸ‘‰šŸ»Spread the word. Tweet, Bluesky, toot, Slack, or carrier‑pigeon this issue to someone who loves Android. Each new subscriber pushes Dispatch closer to sustainability.

šŸ‘‚ Let me hear it!

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

šŸš€šŸš€šŸš€šŸš€šŸš€ AMAZING-LOVED IT!
šŸš€šŸš€šŸš€ PRETTY GOOD!

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

Tech Lead Manager @ Airbnb | Google Developer Expert for Android

Vinay Gaba is a Google Developer Expert for Android and serves as a Tech Lead Manager at Airbnb, where he spearheads the UI Tooling team. His team's mission is to enhance developer productivity through cutting-edge tools leveraging LLMs and Generative AI. Vinay has deep expertise in Android, UI Infrastructure, Developer Tooling, Design Systems and Figma Plugins. Prior to Airbnb, he worked at Snapchat, Spotify, and Deloitte. Vinay holds a Master's degree in Computer Science from Columbia University.

Reply

or to participate.