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

A Composable New World

cmota
August 11, 2021

A Composable New World

As our Twitter streams become flooded with the release of Jetpack Compose 1.0, it's time to jump into the UI declarative world and reform the XML and all of the `findViewById` calls that exist scattered throughout the code.

Join me in this talk to see the first steps into this composable new world and build your first app (with Compose)!

cmota

August 11, 2021
Tweet

More Decks by cmota

Other Decks in Education

Transcript

  1. A Composable new world
    Photo by Greg Rosenke on Unsplash
    @cafonsomota

    View Slide

  2. 👨💻 Android GDE


    🗣 Founder @GDGCoimbra and co-founder @Kotlin_Knights


    ✍ Author @rwenderlich


    🎙 Podcaster wannabe


    🗺 Loves travel, photography and running
    @cafonsomota

    View Slide

  3. 🖥 speakerdeck.com/cmota/a-composable-new-world


    👉 github.com/cmota/unsplash-compose


    🚀 github.com/cmota/kmp-a-multiplatform-triathlon
    @cafonsomota
    Materials

    View Slide

  4. A brief history of (android) time

    View Slide

  5. Android
    * Declarative UI Patterns (I/O’19) - https://www.youtube.com/watch?v=VsStyq4Lzxo
    2008 2009 2010
    1.0
    A lot of Android version in between
    Android Studio
    2013 2014 2015 2016 2017 2018
    ART
    RecyclerView Constraint Layout
    Arch


    Components
    Kotlin

    View Slide

  6. Android
    2019 2021
    Kotlin
    Jetpack Compose 1.0
    2020
    2018aaaaa
    2017asda

    View Slide

  7. Android
    2019 2021
    Kotlin
    Jetpack Compose 1.0
    2020
    2018aaaaa
    2017asda

    View Slide

  8. Jetpack Compose 1.0
    Released: July 28th 2021

    View Slide

  9. Jetpack Compose 1.0.1
    (with Kotlin 1.5.21 support)

    View Slide

  10. dev-reactions/it-works.gif

    View Slide

  11. Before we start

    View Slide

  12. dev-reactions/god-mode.gif

    View Slide

  13. 1. Git Clone


    • github.com/cmota/unsplash-compose


    2. Download Android Studio Arctic Fox*


    • developer.android.com/studio


    3. Create your Unsplash API account


    • unsplash.com/developers
    Materials
    * ⚠ There’s a Specific version for Mac m1

    View Slide

  14. Materials
    Unsplash Compose Android app

    View Slide

  15. Jetpack Compose

    View Slide

  16. What’s Compose?
    verb


    1.

    write or create (a work of art, especially music or poetry).


    "he composed the First Violin Sonata four years earlier"
    Definitions from Oxford Languages

    View Slide

  17. developer.android.com/jetpack/compose

    View Slide

  18. Jetpack Compose
    MODERN FRAMEWORK
    Declarative UI
    Less code
    Smaller APK’s
    Kotlin
    Accelerate development
    Intuitive
    Open-source
    Unbundled from OS

    View Slide

  19. Jetpack Compose
    MODERN FRAMEWORK
    Declarative UI
    Less code
    Kotlin
    Accelerate development
    Intuitive
    Open-source
    Smaller APK’s
    Unbundled from OS

    View Slide

  20. Declarative UI

    View Slide

  21. Declarative UI
    Imperative-UI
    VS

    View Slide

  22. Imperative UI
    Exercise: Implementing a List
    This is item 1
    This is item 2
    This is item 3
    This is item 4
    This is item 5
    This is item 6

    View Slide

  23. Imperative UI
    Exercise: Implementing a List
    1. Create an activity
    MainActivity.kt

    View Slide

  24. Imperative UI
    Exercise: Implementing a List
    1. Create an activity


    2. Create the correspondent xml
    activity_main.xml

    View Slide

  25. Imperative UI
    Exercise: Implementing a List
    1. Create an activity


    2. Create the correspondent xml


    3. Create a fragment
    MainFragment.kt

    View Slide

  26. Imperative UI
    Exercise: Implementing a List
    1. Create an activity


    2. Create the correspondent xml


    3. Create a fragment


    4. Create the correspondent xml
    fragment_main.xml

    View Slide

  27. Imperative UI
    Exercise: Implementing a List
    1. Create an activity


    2. Create the correspondent xml


    3. Create a fragment


    4. Create the correspondent xml


    5. Create a recycler view
    RecyclerView

    View Slide

  28. Imperative UI
    Exercise: Implementing a List
    1. Create an activity


    2. Create the correspondent xml


    3. Create a fragment


    4. Create the correspondent xml


    5. Create a recycler view


    6. Create the adapter
    Adapter

    View Slide

  29. Imperative UI
    Exercise: Implementing a List
    1. Create an activity


    2. Create the correspondent xml


    3. Create a fragment


    4. Create the correspondent xml


    5. Create a recycler view


    6. Create the adapter


    7. Create the correspondent xml for the items
    item_adapter.xml

    View Slide

  30. Imperative UI
    Exercise: Implementing a List
    item_adapter.xml
    files created
    5
    (It can be more if we want to add further customization)
    Lines of code written
    +200
    (Between declarations and xml attributes)

    View Slide

  31. Imperative UI
    Exercise: Implementing a List
    item_adapter.xml
    • Time consuming


    • Error prone


    • Several files created


    • Increasing APK size


    • Coupled components

    View Slide

  32. Imperative UI
    Exercise: Changing the state of a view
    Hello world.

    View Slide

  33. How to change the access
    and change the state of a
    view
    Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    A brief history on
    or

    View Slide

  34. Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    android:Id = “@+id/tv_greeting”
    Text
    TextView greetings = (TextView) findViewById(R.id.tv_greeting)


    greetings.text = “Hello world.”

    View Slide

  35. Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    android:Id = “@+id/tv_greeting”
    Text
    @BindView(R.id.tv_greeting) TextView greetings;


    greetings.text = “Hello world.”
    github.com/JakeWharton/butterknife

    View Slide

  36. Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    android:Id = “@+id/tv_greeting”
    Text
    TextView greetings = (TextView) findViewById(R.id.tv_greeting)


    greetings.text = “Hello world.”

    View Slide

  37. Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    android:Id = “@+id/tv_greeting”
    Text
    TextView greetings = findViewById(R.id.tv_greeting)


    greetings.text = “Hello world.”

    View Slide

  38. Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    android:Id = “@+id/tv_greeting”
    Text
    import kotlinx.android.synthetic.activity_main.*


    tv_greeting.text = “Hello world.”

    View Slide

  39. Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    android:Id = “@+id/tv_greeting”
    Text
    import kotlinx.android.synthetic.activity_main.*


    tv_greeting.text = “Hello world.”
    DEPRECATED

    View Slide

  40. Imperative UI
    Exercise: Changing the state of a view
    Hello world.
    android:Id = “@+id/tv_greeting”
    Text
    buildFeatures.viewBinding true
    private lateinit var binding: FragmentMainBinding


    override fun onCreateView(


    infltr: LayoutInflater,


    container: ViewGroup?,


    state: Bundle?): View {


    binding = FragmentMainBinding.inflate(infltr, container, false)


    return binding.root


    }


    binding.tvGreeting.text = “Hello world.”
    build.gradle

    View Slide

  41. Imperative UI
    android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/View.java
    View.java
    TextView extends

    View Slide

  42. Imperative UI
    android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/View.java
    View.java
    TextView extends
    ImageView

    View Slide

  43. Imperative UI
    android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/View.java
    View.java
    TextView extends
    ImageView
    ViewGroup

    View Slide

  44. Imperative UI
    android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/View.java
    View.java
    TextView extends
    ImageView
    ViewGroup
    extends
    LinearLayout

    View Slide

  45. Imperative UI
    android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/View.java
    View.java
    TextView extends
    ImageView
    ViewGroup
    extends
    LinearLayout
    RelativeLayout

    View Slide

  46. Imperative UI
    android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/View.java
    View.java
    30407 Lines of code
    TextView extends
    ImageView
    ViewGroup
    extends
    LinearLayout
    RelativeLayout

    View Slide

  47. Imperative UI
    With 30407 lines of code and several classes that extend it


    - Difficult to scale


    - Hard to maintain


    - Every change might reflect on a lot of classes


    - Bundled to the OS and OEM’s implementation of these components

    View Slide

  48. Goals
    Unbundle from platform releases


    Faster to implement new designs (views/components)


    Clarify state ownership and event handling
    * Adapted from declarative UI patterns (Google I/O’19) - https://www.youtube.com/watch?v=VsStyq4Lzxo&t

    View Slide

  49. Shifting paradigms
    Imperative UI
    Ui as a function | Kotlin code
    XML
    java | kotlin code
    Layouts


    Attrs


    Styles



    Declarative ui

    View Slide

  50. Shifting paradigms
    Imperative UI
    What should happen
    How it should happen
    Declarative ui

    View Slide

  51. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050

    View Slide

  52. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI

    View Slide

  53. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI
    Showing/hiding badge

    View Slide

  54. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI
    Showing/hiding badge

    View Slide

  55. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI
    Showing/hiding Fire

    View Slide

  56. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI
    Showing/hiding Fire

    View Slide

  57. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI
    Showing/hiding Paper

    View Slide

  58. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI
    Showing/hiding Paper

    View Slide

  59. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    fun updateCount(count: Int) {


    if (count > 0
    &&
    !hasBadge()) {


    addBadge()


    } else if (count
    ==
    0
    &&
    hasBadge()) {


    removeBadge()


    }


    if (count > 99
    &&
    !hasFire()) {


    addFire()


    setBadgeText("99+")


    } else if (count
    <=
    99
    &&
    hasFire()) {


    removeFire()


    }


    if (count > 0
    &&
    !hasPaper()) {


    addPaper()


    } else if (count
    ==
    0
    &&
    hasPaper()) {


    removePaper()


    }


    if (count
    <=
    99) {


    setBadgeText("$count")


    }


    }


    Imperative UI
    Badge number

    View Slide

  60. Shifting paradigms
    medium.com/androiddevelopers/understanding-jetpack-compose-part-1-of-2-ca316fe39050
    @Composable


    fun BadgedEnvelope(count: Int) {


    Envelope(fire=count > 99, paper=count > 0) {


    if (count > 0) {


    Badge(text="$count")


    }


    }


    }
    Declarative UI

    View Slide

  61. Declarative UI
    Winner

    View Slide

  62. Compose

    View Slide

  63. State of compose

    View Slide

  64. State of compose

    View Slide

  65. State of compose
    🤔

    View Slide

  66. • compose.animation


    • Animations library to enrich user experience


    • compose.material


    • Ready to use material design components


    • compose.foundation


    • Building blocks


    • compose.ui


    • Ui components: layout, drawing, and input


    • Compose.runtime


    • Model, state management and core runtime


    • compose.compiler


    • Transform @composable functions and enable optimizations
    Jetpack compose

    View Slide

  67. • compose.animation


    • Animations library to enrich user experience


    • compose.material


    • Ready to use material design components


    • compose.foundation


    • Building blocks


    • compose.ui


    • Ui components: layout, drawing, and input


    • Compose.runtime


    • Model, state management and core runtime


    • compose.compiler


    • Transform @composable functions and enable optimizations
    Jetpack compose
    Compose compiler
    Compose Runtime
    Compose UI Toolkit (ANdroid)
    Compose animation
    Compose UI
    Compose Foundation
    Compose Material

    View Slide

  68. • compose.animation


    • Animations library to enrich user experience


    • compose.material


    • Ready to use material design components


    • compose.foundation


    • Building blocks


    • compose.ui


    • Ui components: layout, drawing, and input


    • Compose.runtime


    • Model, state management and core runtime


    • compose.compiler


    • Transform @composable functions and enable optimizations
    Jetpack compose
    Compose compiler
    Compose UI Toolkit (ANdroid)
    Compose animation
    Compose UI
    Compose Foundation
    Compose Material
    Compose Runtime

    View Slide

  69. Compose compiler
    • Written in Kotlin


    • Transforms @Composable functions into UI


    • Doesn’t use the Annotation Processor


    • The plugin works at system/code generation level


    • Doesn’t impact build times


    • Open source


    • Available in AOSP
    Compose compiler
    Compose UI Toolkit (ANdroid)
    Compose animation
    Compose UI
    Compose Foundation
    Compose Material
    Compose Runtime
    android.googlesource.com/platform/frameworks/support/+/HEAD/compose/compiler

    View Slide

  70. Compose Runtime
    • Platform agnostic


    • DOESN’T KNOW WHAT ANDROID OR UI ARE


    • TrEE MANAGEMENT SOLUTION
    Compose compiler
    Compose Runtime
    Compose UI Toolkit (ANdroid)
    Compose animation
    Compose UI
    Compose Foundation
    Compose Material

    View Slide

  71. Compose COMPILER/Runtime
    What this means is that Compose is, at its core, a general-purpose tool for
    managing a tree of nodes of any type. Well a “tree of nodes” describes just
    about anything, and as a result Compose can target just about anything.
    Jake Wharton - a Jetpack Compose by Any other name
    jakewharton.com/a-jetpack-compose-by-any-other-name/

    View Slide

  72. • compose.animation


    • Animations library to enrich user experience


    • compose.material


    • Ready to use material design components


    • compose.foundation


    • Building blocks


    • compose.ui


    • Ui components: layout, drawing, and input


    • Compose.runtime


    • Model, state management and core runtime


    • compose.compiler


    • Transform @composable functions and enable optimizations
    Jetpack compose
    Compose compiler
    Compose Runtime
    Compose UI Toolkit (ANdroid)
    Compose animation
    Compose UI
    Compose Foundation
    Compose Material

    View Slide

  73. Compose UI toolkit
    • compose.ui


    • Handles Input Management, Drawing, Layouts, etc.


    • Compose.foundation


    • Contains Basic building: Row, Column, Text, iMage, etc.


    • Compose.material


    • Material design system to use on your view components


    • Compose.animation


    • Animations to use easily and out side of the box
    Compose compiler
    Compose Runtime
    Compose UI Toolkit (ANdroid)
    Compose animation
    Compose Foundation
    Compose Material
    Compose UI

    View Slide

  74. Compose UI
    Raspberry pi
    compose
    Compose compiler
    Compose Runtime Compose UI
    ANdroid
    Compose UI
    Desktop
    Compose UI
    Web
    Compose UI
    Console

    View Slide

  75. blog.jetbrains.com/kotlin/2021/08/compose-multiplatform-goes-alpha/

    View Slide

  76. Should I switch to compose?

    View Slide

  77. Apps in Production*
    *doesn’t mean they are 100% written in Compose

    View Slide

  78. Jetpack compose - before and after
    By Chris Banes
    github.com/chrisbanes/tivi

    View Slide

  79. medium.com/androiddevelopers/jetpack-compose-before-and-after-8b43ba0b7d4f
    Jetpack compose - before and after
    By Chris Banes
    APK Size
    1250
    2500
    3750
    5000
    Pre-Compose (4.49 MB) Compose (2.39 MB)
    4.14 MB 2.32 MB
    69 KB
    347 KB
    4.49MB
    2.32 MB
    -46%

    View Slide

  80. medium.com/androiddevelopers/jetpack-compose-before-and-after-8b43ba0b7d4f
    Jetpack compose - before and after
    By Chris Banes
    Method
    12500
    25000
    37500
    50000
    Pre-Compose (40029) Compose (23689)
    40029 23689
    40029 methods
    23689 methods
    -17%
    Count

    View Slide

  81. medium.com/androiddevelopers/jetpack-compose-before-and-after-8b43ba0b7d4f
    Jetpack compose - before and after
    By Chris Banes
    Lines of
    5000
    10000
    15000
    20000
    Pre-Compose (19478) Compose (15407)
    15827 14606
    19478 Lines of code
    15407 lines of code
    Source
    Code
    3651
    801

    View Slide

  82. medium.com/androiddevelopers/jetpack-compose-before-and-after-8b43ba0b7d4f
    Jetpack compose - before and after
    By Chris Banes
    Build
    30
    60
    90
    120
    Pre-Compose (108,71 s) Compose (76,96 s)
    108,71 76,96
    108,71 seconds
    76,96 seconds
    -29%
    Speed

    View Slide

  83. YES
    Should I switch to compose?

    View Slide

  84. Compose-ready libraries

    View Slide

  85. github.com/google/accompanist
    Accompanist
    📐 Insets


    🍫 System UI Controller


    🎨 AppCompat Theme Adapter


    🧭✨Navigation-Animation


    🧭🎨 Navigation-Material


    🖌 Drawable Painter


    ⬇ Swipe to Refresh
    📖 Pager


    📫 Permissions


    ⏳ Placeholder


    🌊 Flow Layouts

    View Slide

  86. github.com/google/accompanist
    Accompanist
    📐 Insets


    🍫 System UI Controller


    🎨 AppCompat Theme Adapter


    🧭✨Navigation-Animation


    🧭🎨 Navigation-Material


    🖌 Drawable Painter


    ⬇ Swipe to Refresh
    📖 Pager


    📫 Permissions


    ⏳ Placeholder


    🌊 Flow Layouts
    Keyboard IME animations are now
    available starting on minSDK 21
    (through Jetpack Compose)

    View Slide

  87. coil-kt.github.io/coil/compose/
    Coil

    View Slide

  88. lottie
    github.com/airbnb/lottie/blob/master/android-compose.md

    View Slide

  89. How to Start?

    View Slide

  90. How to Start?

    View Slide

  91. Configuration
    android {


    defaultConfig {


    minSdk 21





    }


    kotlinOptions {


    jvmTarget = '1.8'


    useIR = true


    }


    buildFeatures {


    compose true


    }




    composeOptions {


    kotlinCompilerExtensionVersion compose_version


    kotlinCompilerVersion '1.5.10'


    }


    }
    build.gradle

    View Slide

  92. Configuration
    android {


    defaultConfig {


    minSdk 21





    }


    kotlinOptions {


    jvmTarget = '1.8'


    useIR = true


    }


    buildFeatures {


    compose true


    }




    composeOptions {


    kotlinCompilerExtensionVersion compose_version


    kotlinCompilerVersion '1.5.10'


    }


    }
    build.gradle

    View Slide

  93. Configuration
    android {


    defaultConfig {


    minSdk 21





    }


    kotlinOptions {


    jvmTarget = '1.8'


    useIR = true


    }


    buildFeatures {


    compose true


    }




    composeOptions {


    kotlinCompilerExtensionVersion '1.0.0'


    kotlinCompilerVersion '1.5.10'


    }


    }
    build.gradle

    View Slide

  94. Configuration
    android {


    defaultConfig {


    minSdk 21





    }


    kotlinOptions {


    jvmTarget = '1.8'


    useIR = true


    }


    buildFeatures {


    compose true


    }




    composeOptions {


    kotlinCompilerExtensionVersion '1.0.0'


    kotlinCompilerVersion '1.5.10'


    }


    }
    build.gradle

    View Slide

  95. Configuration
    dependencies {


    implementation "androidx.compose.ui:ui:1.0.0"


    implementation "androidx.compose.material:material:1.0.0"


    implementation "androidx.compose.ui:ui-tooling-preview:1.0.0"


    implementation "androidx.activity:activity-compose:1.3.1"


    }


    build.gradle

    View Slide

  96. Adding text
    XML
    Hello world!
    Kt

    View Slide

  97. Adding text


    android:id="@+id/tv_greetings"


    android:layout_width="wrap_content"


    android:layout_height=“wrap_content"


    android:text="Hello world!"
    />
    XML
    Hello world!
    Without Compose

    View Slide

  98. Adding text


    android:id="@+id/tv_greetings"


    android:layout_width="wrap_content"


    android:layout_height=“wrap_content"


    android:text="Hello world!"
    />
    XML
    Hello Android!
    Without Compose
    val greetings = findViewById(R.id.tv_greetings)


    greetings.text = "Hello Android!”


    Kt

    View Slide

  99. Adding text
    Hello world!
    With Compose
    Text(text = "Hello world!”) Kt

    View Slide

  100. Adding text
    Hello world!
    With compose
    @Composable


    fun Greeting(name: String) {


    Text(text = "Hello $name!")


    }


    Kt

    View Slide

  101. Adding text
    With compose
    @Composable


    fun Greeting(name: String) {


    Text(text = "Hello $name!")


    }


    Kt

    View Slide

  102. Adding text
    With compose
    @Composable


    fun Greeting(name: String) {


    Text(text = "Hello $name!")


    }


    Kt

    View Slide

  103. Adding text
    With compose
    @Composable


    fun Greeting(name: String) {


    Text(text = "Hello $name!")


    }


    Kt

    View Slide

  104. Adding text
    With compose
    @Composable


    fun Greeting(name: String) {


    Text(text = "Hello $name!")


    }


    Kt

    View Slide

  105. View Groups
    Hello world!
    XML
    Number of co
    ff
    ees: 0

    View Slide

  106. View Groups
    Hello world!
    Without compose





    xmlns:android="http:
    //
    schemas.android.com/apk/res/android"


    android:orientation="vertical"


    android:layout_width="match_parent"


    android:layout_height="match_parent">




    android:id="@+id/tv_greetings"


    android:layout_width="wrap_content"


    android:layout_height="wrap_content"


    android:text="Hello world!"
    />



    android:layout_width="wrap_content"


    android:layout_height="wrap_content"


    android:text="Number of coffees: 0"
    />


    LinearLayout>


    XML
    Number of co
    ff
    ees: 0

    View Slide

  107. View Groups
    Hello world!
    With compose
    @Composable


    fun Greeting(name: String) {


    Text(text = "Hello $name!")


    }


    Kt

    View Slide

  108. View Groups
    Hello world!
    With compose
    @Composable


    fun Greeting(name: String) {


    Text(text = "Hello $name!”)


    Text(text = "Number of coffees: 0")


    }


    Kt
    Number of co
    ff
    ees: 0

    View Slide

  109. View Groups
    Hello world!
    With compose
    @Composable


    fun Greeting(name: String) {


    Column {


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt
    Number of co
    ff
    ees: 0

    View Slide

  110. View Groups
    Hello world!
    With compose
    @Composable


    fun Greeting(name: String) {


    Column {


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt
    Number of co
    ff
    ees: 0

    View Slide

  111. View Groups
    Hello world!
    With compose
    @Composable


    fun Greeting(name: String) {


    Row {


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt
    Number of co
    ff
    ees: 0

    View Slide

  112. Number of co
    ff
    ees: 0
    View Groups
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(


    modifier = Modifier.background(Color.Green)


    ){


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt
    Hello world!

    View Slide

  113. View Groups
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(


    modifier = Modifier.background(Color.Green)


    ){


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt
    Hello world!
    Number of co
    ff
    ees: 0

    View Slide

  114. Hello world!
    Number of co
    ff
    ees: 0
    View Groups
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(


    modifier = Modifier.fillMaxSize()


    .background(Color.Green)


    ){


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt

    View Slide

  115. Hello world!
    Number of co
    ff
    ees: 0
    View Groups
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(


    modifier = Modifier.fillMaxSize()


    .background(Color.Green)


    .padding(16.dp)


    ){


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt

    View Slide

  116. Hello world!
    Number of co
    ff
    ees: 0
    View Groups
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(


    modifier = Modifier.fillMaxSize()


    .background(Color.Green)


    .padding(16.dp),


    horizontalAlignment = Alignment.CenterHorizontally,


    verticalArrangement = Arrangement.Center


    ){


    Text(text = "Hello $name!")


    Text(text = "Number of coffees: 0")


    }


    }


    Kt

    View Slide

  117. Hello world!
    View Groups
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(


    modifier = Modifier.fillMaxSize()


    .background(Color.Green)


    .padding(16.dp),


    horizontalAlignment = Alignment.CenterHorizontally,


    verticalArrangement = Arrangement.Center


    ){


    Text(


    text = "Hello $name!”,


    color = Color.White


    )


    Text(text = "Number of coffees: 0")


    }


    }


    Kt
    Number of co
    ff
    ees: 0

    View Slide

  118. Hello world!
    Images
    XML
    Number of co
    ff
    ees: 0

    View Slide

  119. Hello world!
    Images
    Without compose










    android:layout_width="wrap_content"


    android:layout_height="wrap_content"


    android:src="@drawable/ic_launcher"


    android:contentDescription="@string/app_name"
    />


    LinearLayout>


    XML
    Number of co
    ff
    ees: 0

    View Slide

  120. Hello world!
    Images
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(…) {


    Text(


    text = "Hello $name!",


    color = Color.White


    )


    Text(text = "Number of coffees: 0")


    Image(


    painter = painterResource(id = R.drawable.ic_launcher),


    contentDescription = stringResource(id = R.string.app_name)


    )


    }


    }


    Kt
    Number of co
    ff
    ees: 0

    View Slide

  121. Hello world!
    Images
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(…) {


    Text(


    text = "Hello $name!",


    color = Color.White


    )


    Text(text = "Number of coffees: 0")


    Image(


    painter = painterResource(id = R.drawable.ic_launcher),


    contentDescription = stringResource(id = R.string.app_name)


    )


    }


    }


    Kt
    Number of co
    ff
    ees: 0

    View Slide

  122. Hello world!
    Button
    XML
    Number of co
    ff
    ees: 0
    +

    View Slide

  123. Hello world!
    Button
    Without compose










    android:layout_width="wrap_content"


    android:layout_height="wrap_content"


    android:text="+"
    />


    LinearLayout>


    XML
    Number of co
    ff
    ees: 0
    +

    View Slide

  124. Hello world!
    Button
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(…) {





    Text(text = "Number of coffees: 0")





    Button(onClick = {
    /*
    TODO
    */
    }) {


    Text("+")


    }


    }


    }


    Kt
    Number of co
    ff
    ees: 0
    +

    View Slide

  125. Hello world!
    Button
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(…) {





    Text(text = "Number of coffees: 0")





    Button(onClick = {
    /*
    TODO
    */
    }) {


    Text("+")


    }


    }


    }


    Kt
    Number of co
    ff
    ees: 0
    +

    View Slide

  126. Hello world!
    State
    Kt
    Number of co
    ff
    ees: 0
    +

    View Slide

  127. Hello world!
    State
    Without compose
    var count = 0


    binding.tvMessage = getString(R.string.number_coffee, count)


    binding.btn_increment.setOnClickListener {


    count
    ++

    }


    Kt
    Number of co
    ff
    ees: 0
    +

    View Slide

  128. Hello world!
    State
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(…) {





    val count = remember { mutableStateOf(0) }


    Text(text = "Number of coffees taken: ${count.value}")





    Button(onClick = { count.value = count.value + 1 }) {


    Text("+")


    }


    }


    }


    Kt
    Number of co
    ff
    ees: 0
    +

    View Slide

  129. Hello world!
    State
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(…) {





    val count = remember { mutableStateOf(0) }


    Text(text = "Number of coffees taken: ${count.value}")





    Button(onClick = { count.value = count.value + 1 }) {


    Text("+")


    }


    }


    }


    Kt
    Number of co
    ff
    ees: 0
    +

    View Slide

  130. Hello world!
    State
    With compose
    @Composable


    fun Greeting(name: String) {


    Column(…) {





    val count = remember { mutableStateOf(0) }


    Text(text = "Number of coffees taken: ${count.value}")





    Button(onClick = { count.value = count.value + 1 }) {


    Text("+")


    }


    }


    }


    Kt
    Number of co
    ff
    ees: 0
    +

    View Slide

  131. Live Demo

    View Slide

  132. dev-reactions/live-coding.gif

    View Slide

  133. Resources

    View Slide

  134. • Jetpack Compose samples (Google)


    • github.com/android/compose-samples


    • A curated list of Jetpack Compose libraries, projects, articles and resources


    • github.com/jetpack-compose/jetpack-compose-awesomeAnimations library to enrich user experience


    • Jetpack Compose Catalog


    • jetpackcompose.app


    • Jetpack/JetBrains Compose Playground


    • foso.github.io/Jetpack-Compose-Playground/


    • Community


    • twitch.tv/intelligibabble


    • joebirch.co/tag/jetpack-compose/


    • jorgecastillo.dev/
    Resources

    View Slide

  135. A Composable new world
    Photo by Greg Rosenke on Unsplash
    @cafonsomota

    View Slide