Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Blazing Fast UI Development with Compose Hot Re...

Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)

Avatar for Márton Braun

Márton Braun

June 26, 2025
Tweet

More Decks by Márton Braun

Other Decks in Programming

Transcript

  1. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-alpha11" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" }
  2. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-alpha11" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } !// Default in Kotlin 2.2.0 composeCompiler { featureFlags.add(ComposeFeatureFlag.OptimizeNonSkippingGroups) }
  3. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-alpha11" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } !// Default in Kotlin 2.2.0 composeCompiler { featureFlags.add(ComposeFeatureFlag.OptimizeNonSkippingGroups) }
  4. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-alpha11" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } !// Default in Kotlin 2.2.0 composeCompiler { featureFlags.add(ComposeFeatureFlag.OptimizeNonSkippingGroups) }
  5. How does it work? Gradle Recompiler Dev Tooling Your app’s

    code JetBrains Runtime Gradle Hot Reload Agent
  6. How does it work? Gradle Recompiler Dev Tooling Your app’s

    code JetBrains Runtime Gradle Hot Reload Agent
  7. How does it work? Gradle Recompiler Dev Tooling Your app’s

    code JetBrains Runtime Gradle Hot Reload Agent
  8. How does it work? Gradle Recompiler Dev Tooling Your app’s

    code JetBrains Runtime Gradle Hot Reload Agent IDE
  9. DCEVM class Offset( val x: Int, val y: Int, )

    Dynamic Code Evolution Virtual Machine Side Universe Class Loader class Offset( val x: Int, ) Current Class Loader
  10. DCEVM class Offset( val x: Int, val y: Int, )

    Dynamic Code Evolution Virtual Machine Current Class Loader
  11. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of class Offset( val x: Int, )
  12. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of class Offset( val x: Int, val y: Int, ) +
  13. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of Offset@235235 Offset@534643 Offset@734 class Offset( val x: Int, val y: Int, ) +
  14. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of Offset@235235 Offset@534643 Offset@734 42 Header 13 Header Head class Offset( val x: Int, val y: Int, ) +
  15. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of Offset@235235 Offset@534643 Offset@734 42 Header 13 Header Head 0 0 class Offset( val x: Int, val y: Int, ) +
  16. DCEVM Dynamic Code Evolution Virtual Machine Offset@235235 Offset@534643 Offset@734 42

    Header 13 Header Head 0 0 class Offset( val x: Int, val y: Int, ) +
  17. Compose diffing fun mediumPadding() = 16.dp @Composable fun Counter() {

    var counter by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } }
  18. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  19. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  20. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  21. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  22. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here’s a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  23. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here’s a wonderful counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  24. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here’s a wonderful counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  25. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") } } } } CS$SomeWidgetKt$lambda-1.class Function3<ColumnScope, Composer, ...>
  26. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") } } } } CS$SomeWidgetKt$lambda-2.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1.class Function3<ColumnScope, Composer, ...>
  27. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") CS$SomeWidgetKt$lambda-3.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-2.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1.class Function3<ColumnScope, Composer, ...> } } } }
  28. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") Surface { Text("D") } } } } } CS$SomeWidgetKt$lambda-3.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-2.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1.class Function3<ColumnScope, Composer, ...>
  29. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") Surface { Text("D") } } } } } CS$SomeWidgetKt$lambda-3.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-2.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-?.class Function2<Composer, ...>
  30. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") Surface { Text("D") } } } } } CS$SomeWidgetKt$lambda-4.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-3.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-2.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1.class Function2<Composer, ...>
  31. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") Surface { Text("D") } } } } } CS$SomeWidgetKt$lambda-4.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-3.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-2.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1.class Function2<Composer, ...> this: ColumnScope this: ColumnScope this: ColumnScope
  32. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") Surface { Text("D") } } } } } CS$SomeWidgetKt$lambda-4.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-3.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-2.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1.class Function2<Composer, ...>
  33. Structural changes CS$SomeWidgetKt$lambda-3523533.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1995335.class Function3<ColumnScope, Composer, ...>

    CS$SomeWidgetKt$lambda-1245234.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-5235232.class Function2<Composer, ...> } } } } @Composable fun SomeWidget() { Card { Text("A") Card { Text("B") Card { Text("C") Surface { Text("D") }
  34. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") CS$SomeWidgetKt$lambda-3523533.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1995335.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1245234.class Function3<ColumnScope, Composer, ...> } } } }
  35. Structural changes @Composable fun SomeWidget() { Card { Text("A") Card

    { Text("B") Card { Text("C") Surface { Text("D") } CS$SomeWidgetKt$lambda-3523533.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-1995335.class Function3<ColumnScope, Composer, ...> } } } } CS$SomeWidgetKt$lambda-1245234.class Function3<ColumnScope, Composer, ...> CS$SomeWidgetKt$lambda-5235232.class Function2<Composer, ...>
  36. zsmb.co/talks Márton Braun @zsmb.co Compose Hot Reload jb.gg/chr KotlinConf app

    jb.gg/kc-app Sebastian Sellmair’s content KotlinConf talk jb.gg/kc25-chr YouTube youtube.com/@s.sellmair Blog blog.sellmair.io Blazing Fast UI Development with