DEV Community

Cover image for Compose Recomposition Highlighter: On-Device Visual Recomposition Heatmap for Android
Zakayo Thuku
Zakayo Thuku

Posted on Originally published at github.com

Compose Recomposition Highlighter: On-Device Visual Recomposition Heatmap for Android

App Screenshot

In Jetpack Compose, the declarative UI paradigm simplifies state synchronization, but unintentional recomposition cascades remain one of the primary causes of UI micro-stutters (jank) and battery drain.

While the desktop Android Studio Layout Inspector provides recomposition counts, diagnosing performance regressions on physical devices in real-world conditions (without being tethered to a workstation over USB) has historically been challenging.

To solve this, we built compose-recomposition-highlighter — an open-source, on-device visual performance auditor for Jetpack Compose.


🏗️ Architectural Overview & How It Works

compose-recomposition-highlighter operates through a lightweight modifier and a thread-safe recomposition registry:

  1. Draw-Phase Tracking: Uses Modifier.drawWithCache to read and increment render passes during the draw phase, ensuring the tracking itself does not trigger additional recomposition loops.
  2. Dynamic Heatmap Mapping: Maps the render frequency to a high-contrast color gradient:
    • 🟢 Green (1–2x): Healthy, expected recomposition.
    • 🟡 Yellow (3–5x): Moderate activity.
    • 🟠 Orange (6–9x): High recomposition rate.
    • 🔴 Red (10x+): Severe hotspot / infinite recomposition alert.
  3. Hotspot Velocity Metrics: Calculates velocity (recomps/sec) to help you spot runaway loops immediately.

🛠️ Step-by-Step Implementation Guide

1. Add Gradle Dependency

Add the library from Maven Central using debugImplementation so it is automatically stripped from release builds:

dependencies {
    // Debug builds: full highlighter engine + UI overlay
    debugImplementation("io.github.zakayothuku:compose-recomposition-highlighter:1.0.0")

    // Release builds: zero-overhead no-op artifact
    releaseImplementation("io.github.zakayothuku:compose-recomposition-highlighter-noop:1.0.0")
}
Enter fullscreen mode Exit fullscreen mode

2. Attach the Modifier to Target Composables

Attach .recompositionHighlighter() to any composable you want to monitor:

@Composable
fun UserProfileCard(
    user: UserUiModel,
    onFollowClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Card(
        modifier = modifier
            .fillMaxWidth()
            .recompositionHighlighter(tag = "UserProfileCard")
            .padding(16.dp)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(text = user.name, style = MaterialTheme.typography.titleMedium)
            Text(text = user.bio, style = MaterialTheme.typography.bodyMedium)
            Button(onClick = onFollowClick) {
                Text(text = if (user.isFollowing) "Following" else "Follow")
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Mount the Floating Performance HUD

In your root application screen or navigation host, wrap your content with ComposeRecompositionOverlay:

@Composable
fun MainAppScreen() {
    Box(modifier = Modifier.fillMaxSize()) {
        // App Navigation & Screens
        AppNavigationGraph()

        // Floating Draggable On-Device Recomposition Monitor
        ComposeRecompositionOverlay(
            enabled = BuildConfig.DEBUG,
            showCountBadges = true,
            warningThreshold = 5,
            criticalThreshold = 10
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

🔍 Common Jetpack Compose Traps You Will Catch

  1. Unstable Lambda Parameters: Passing non-memoized lambdas (e.g. { viewModel.doSomething(item.id) }) inside LazyColumn items causing whole-list invalidations.
  2. Un-remembered Derived Computations: Calculating heavy sorted lists or date formats directly inside the composable body without remember { ... }.
  3. Over-Observing StateFlows: Observing a coarse-grained UI state object when a composable only needs a single primitive boolean.

👉 GitHub Repository: github.com/zakayothuku/compose-recomposition-highlighter

Top comments (0)