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

Connect Recharge: What does Recomposition mean to your app?

Connect Recharge: What does Recomposition mean to your app?

LITE version

PRESENTED AT:
Connect Recharge 2022

https://hopin.com/events/connect-recharge-2022/registration?code=wwK1JKQKXBSzI6RaQZcehxqtr

DESCRIPTION:
You’ve heard a lot that Jetpack Compose is a declarative UI toolkit and it recomposes only the components that changed. But what does it exactly mean? How does it apply not only in the scale of one composable function but the entire app? Well, it turns out there is more than meets the eye when it comes to recomposition, and in this talk, we will deep dive into its benefits, costs, and gotchas. You’ll learn some practical tips to efficiently build functions in Jetpack Compose.

MORE TALKS & ARTICLES FROM ME: https://cupsofcode.com/talks/

Aida Issayeva

May 26, 2022
Tweet

More Decks by Aida Issayeva

Other Decks in Programming

Transcript

  1. What does
    Recomposition mean to
    your app?
    Aida Issayeva
    Lite

    View Slide

  2. About me
    🤖 Android GDE
    󰠁 Sr. Software Engineer
    󰠅 Instructor
    🐦 @aida_isay
    🌐 cupsofcode.com
    📽 @aida_isay

    View Slide

  3. TODAY’S
    AGENDA
    02
    Smart Recomposition
    03
    Tools to detect & debug
    04
    Practical tips
    05
    01
    What is Recomposition?
    Jetpack Compose Paradigm

    View Slide

  4. Jetpack Compose paradigm
    UI widgets are functions
    They are stateless
    Different arguments, passed to
    the functions, trigger updates

    View Slide

  5. SlotTable
    Android OS
    Composer
    Applier
    UI Node Tree
    State Snapshot System
    Change List
    Applier

    View Slide

  6. 01 Jetpack Compose Paradigm
    Compose Phases
    1
    Composition
    Calls composable functions and
    creates a description of the UI
    2
    Layout
    Measures the layout elements
    and their children and places
    them on the screen
    3
    Drawing
    Draws the UI elements to the
    screen

    View Slide

  7. Composition
    is a process of executing
    composable functions

    View Slide

  8. SlotTable
    Android OS
    Com
    poser
    Applier
    UI Node Tree
    State Snapshot System
    Change List

    View Slide

  9. What is
    recomposition?

    View Slide

  10. Recomposition
    is a re-execution of composable functions in
    response to state changes

    View Slide

  11. Recomposition in SlotTable:
    example 1
    @Composable
    fun Card() {
    val counter = remember {
    mutableStateOf(0)
    }
    Column {
    Text(text = "Compose")
    Button(onClick = {
    counter.value++
    }) {
    Text(text = "Click me $counter")
    }
    }
    }
    02 What is recomposition
    Group(456)
    …..
    Group(789)
    “Compose”
    Group(101)
    “Click me 0”
    C
    A
    R
    D
    C
    O
    L
    U
    M
    N
    B
    U
    T
    T
    O
    N
    { ... }
    Group(123)
    State(0)
    R
    E
    M
    E
    M
    B
    E
    R

    View Slide

  12. Recomposition in SlotTable:
    example 1
    @Composable
    fun Card() {
    val counter = remember {
    mutableStateOf(0)
    }
    Column {
    Text(text = "Compose")
    Button(onClick = {
    counter.value++
    }) {
    Text(text = "Click me $counter")
    }
    }
    }
    02 What is recomposition
    Group(456)
    …..
    Group(789)
    “Compose”
    Group(101)
    “Click me 0”
    C
    A
    R
    D
    C
    O
    L
    U
    M
    N
    B
    U
    T
    T
    O
    N
    { ... }
    Group(123)
    State(0)
    R
    E
    M
    E
    M
    B
    E
    R

    View Slide

  13. Recomposition in SlotTable:
    example 1
    @Composable
    fun Card() {
    val counter = remember {
    mutableStateOf(0)
    }
    Column {
    Text(text = "Compose")
    Button(onClick = {
    counter.value++
    }) {
    Text(text = "Click me $counter")
    }
    }
    }
    02 What is recomposition
    Group(456)
    …..
    Group(789)
    “Compose”
    Group(101)
    “Click me 1”
    C
    A
    R
    D
    C
    O
    L
    U
    M
    N
    B
    U
    T
    T
    O
    N
    { ... }
    Group(123)
    State(1)
    R
    E
    M
    E
    M
    B
    E
    R

    View Slide

  14. Recomposition in SlotTable:
    example 2
    @Composable
    fun Card() {
    val counter = remember {
    mutableStateOf(0)
    }
    Column {
    Text(text = "Compose $counter")
    Button(onClick = {
    counter.value++
    }) {
    Text(text = "Click me")
    }
    }
    }
    02 What is recomposition
    Group(456)
    …..
    Group(789)
    “Compose 0”
    Group(101)
    “Click me”
    C
    A
    R
    D
    C
    O
    L
    U
    M
    N
    B
    U
    T
    T
    O
    N
    { ... }
    Group(123)
    State(0)
    R
    E
    M
    E
    M
    B
    E
    R

    View Slide

  15. Recomposition in SlotTable:
    example 2
    @Composable
    fun Card() {
    val counter = remember {
    mutableStateOf(0)
    }
    Column {
    Text(text = "Compose $counter")
    Button(onClick = {
    counter.value++
    }) {
    Text(text = "Click me")
    }
    }
    }
    02 What is recomposition
    Group(456)
    …..
    Group(789)
    “Compose 1”
    Group(101)
    “Click me”
    C
    A
    R
    D
    C
    O
    L
    U
    M
    N
    B
    U
    T
    T
    O
    N
    { ... }
    Group(123)
    State(0)
    R
    E
    M
    E
    M
    B
    E
    R

    View Slide

  16. 02 What is recomposition
    Compose Phases
    1
    Composition
    Calls composable functions and
    creates a description of the UI
    2
    Layout
    Measures the layout elements
    and their children and places
    them on the screen
    3
    Drawing
    Draws the UI elements to the
    screen

    View Slide

  17. Smart
    recomposition

    View Slide

  18. Inputs are stable
    Smart recomposition is an intelligent way to skip the
    recomposition of composable functions when their

    View Slide

  19. Stable type contract rules:
    RULE 1
    The result of calls
    for two instances to
    `equals()` function
    will always be the
    same for the same
    two instances
    RULE 2
    When a public
    property of the type
    changes, Composition
    is notified
    RULE 3
    All public properties
    of the type are also
    stable

    View Slide

  20. Stable property types:
    Primitive types:
    Int, Boolean, Long, Char, Float
    String
    Annotated with @Stable

    View Slide

  21. What about custom
    data types?
    03 Smart Recomposition

    View Slide

  22. Exceptions:
    1. Enum
    2. Enum Entry
    3. Interface
    4. Annotation
    5. Companion Object
    6. Inline
    7. Anonymous object
    8. Expect element
    9. Inner class
    03 Smart Recomposition
    Inferring Class stability
    ● visits each eligible class
    ● annotates with @StabilityInferred
    ● helps compiler to determine what
    to recompose

    View Slide

  23. Tools to
    detect & debug
    recomposition

    View Slide

  24. 1. Recompose Highlighter
    ➢ Google Play team introduced the
    modifier
    ➢ Use this link below to check out the
    code snippet
    04 Tools to detect

    View Slide

  25. 2. Log Statements
    04 Tools to detect
    ➢ Ancient and the most reliable.
    ➢ Android Studio Electric Eel has an
    automatic support for it.
    ➢ Wrapped as a modifier function.
    Check out the code snippet below

    View Slide

  26. 3. Compose Compiler Metrics
    04 Tools to detect
    {
    "skippableComposables" :
    64,
    "restartableComposables" :
    76,
    "readonlyComposables" :
    0,
    "totalComposables" : 76
    }
    ➢ Full analysis
    ➢ Restartable & !skippable = ⛳
    ➢ Check out the code snippet below
    for integration details

    View Slide

  27. Practical tips to
    leverage smart
    recomposition

    View Slide

  28. 1. Break down composable
    functions
    /**
    * 👍 : only associated column with changes gets
    recomposed.
    */
    @Composable
    fun GoodGreetingsTip1() {
    Column {
    Greeting("Android", 1, Gray200)
    Greeting("Compose", 2, Brown200)
    }
    }
    @Composable
    fun Greeting(name: String, columnNumber: Int,
    background: Color) {
    Column {
    . . .
    }
    }
    05 Practical tips

    View Slide

  29. 2. Use the key composable
    /**
    * 👍 : the key is set, and when item in the middle is
    removed, only LazyColumn gets recomposed
    * and not its children
    */
    @Composable
    fun GoodGreetingsTip2(fruits: List) {
    LazyColumn(
    modifier = Modifier
    .recompositionCounter("lazyColumn")
    ) {
    items(
    items = fruits,
    key = { it }
    ) { fruit ->
    Item(fruit)
    }
    }
    }
    05 Practical tips

    View Slide

  30. 3. Read the state value at the
    lowest composable function
    /**
    * 👍 : only inner column and its children get
    recomposed, because the read happens
    * in one of the children.
    */
    @Composable
    fun GoodGreetingsTip3(cardInfo: () -> CardInfo) {
    Column {
    UpperRow()
    GoodRow(cardInfo = cardInfo)
    }
    }
    @Composable
    private fun GoodRow(cardInfo: () -> CardInfo) {
    Row {
    GoodInnerColumn(cardInfo = cardInfo)
    }
    }
    05 Practical tips

    View Slide

  31. 4. Use modifier lambdas
    /**
    * 👍: With the receiver lambda function
    (Modifier.offset{}) in place, this composable
    function doesn't get recomposed.
    */
    @Composable
    private fun GoodGreetingsTip4(yAxis: () -> Int) {
    Row(
    modifier = Modifier
    .offset {
    IntOffset(y = yAxis(), x = 0)
    },
    verticalAlignment = Alignment.Bottom
    ) {
    . . .
    }
    }
    05 Practical tips

    View Slide

  32. IMPORTANT 1
    Move any logic out
    of the composable
    functions to
    viewmodels,
    presenters, etc
    5. Tips worth re-repeating
    IMPORTANT 2
    Don’t create
    dependable
    composable functions
    on the result of other
    composables functions
    IMPORTANT 3
    Avoid any
    side-effects in the
    composable
    functions, because
    they can run in
    parallel

    View Slide

  33. Resources
    1. Jetpack Compose Internals
    2. Jetpack Compose source code
    3. Understanding Jetpack Compose — part 1 of 2
    4. Understanding Jetpack Compose — part 2 of 2
    5. Recomposition made easy
    6. RecomposeHighlighter code snippet
    7. Compose Compiler Metrics
    8. A historical introduction to the Compose reactive state
    model
    9. What is “donut-hole” skipping in Jetpack Compose?
    10. Compose performance
    11. Composable Metrics
    12. Thinking in Compose
    13. Jetpack Compose Phases
    14. Jetpack Compose Lifecycle
    Resources
    Recomposition tips
    code samples

    View Slide

  34. THANK YOU
    www.cupsofcode.com
    Code | Live | Grow
    @aida_isay

    View Slide