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

Let's Talk Composing UI :: DevFest New Delhi

Let's Talk Composing UI :: DevFest New Delhi

Visit: https://rivu.dev for more info.
While Developing Apps, following a Reactive Architecture (for example MVI, Mobius, Redux and even MVVM) & Single Source of Truth can get you some big wins including but not limited to, Loose Coupling & Separation of Concerns, Code Testability and easy debugging, unidirectional data, etc. However, unlike Web, where Reactive Architectures are the norm, in Android, we need to opt for Reactive Architecture considering few tradeoffs (time to market, learning curve, etc.), as it’s not natural in Android.

What do I mean by saying Reactive architecture is not natural in Android? Just like web frontends, Android apps revolve around the UI, everything we do in our Android apps has some direct or indirect relation with the UI, and the Android UI framework is imperative itself.
While the Android Platform team kept adding more and more types of Views (such as Constraint Layout, RecyclerView or more recent Motion Layout), they didn’t change the nature of UI framework itself since the beginning of android development. This was majorly due to language and tooling limitations (limited by the technologies of that time).

Google announced official support for Kotlin 2 years back, and now major numbers of professional Android Developers worldwide already adopted Kotlin, which made it easier for Google to go Kotlin first in this IO19. Kotlin comes with many perks, some of them are Functional Programming support, compiler plugin capabilities and most importantly huge support on building DSLs at ease.

What relation does Koltin have with Reactive applications? In this IO19, Google announced Jetpack Compose (https://developer.android.com/jetpack/compose/), a new (still-in-development) next generation, Kotlin based, reactive cum declarative UI toolkit, backed by principals like Single Source of Truth, Unidirectional Data Flow, Functional Programming (especially function composition and effects).

This new UI toolkit would require a radical shift in our thought process about app architectures UI programming. In this talk, we would see how we can create and interact with UI with Jetpack Compose and how different it is from the present Android framework. We will also look into examples of some code patterns and ideas of from a few famous platforms such as Vue.js, React, Flutters, etc., and how these patterns and are adopted in Jetpack Compose.

Rivu Chakraborty

September 29, 2019
Tweet

More Decks by Rivu Chakraborty

Other Decks in Programming

Transcript

  1. Hello Delhi!!
    Slide Design by instagram.com/mohijeet/
    Rivu Chakraborty

    View Slide

  2. Let’s Talk Composing UI
    Rivu Chakraborty
    https://rivu.dev
    New Delhi

    View Slide

  3. Rivu Chakraborty
    About Me
    ● https://rivu.dev
    ● Sr Software Engineer (Android) - BYJU’S
    ● Instructor - Caster.io
    ● Google Certified Associate Android Developer
    ● Speaks on Kotlin / Android
    ● Author - Reactive Programming in Kotlin
    ● Author - Functional Kotlin
    ● Author - Hands-On Data Structures and Algorithms with Kotlin

    View Slide

  4. View Slide

  5. @intelligibabble
    http://intelligiblebabble.com/
    Big Shout Out
    Leland Richardson

    View Slide

  6. Before We begin
    ● Android Developers
    @rivuchakraborty
    https://rivu.dev

    View Slide

  7. ● Android Developers
    ● Used Kotlin
    @rivuchakraborty
    https://rivu.dev
    Before We begin

    View Slide

  8. ● Android Developers
    ● Used Kotlin
    ● Loves writing XML?
    @rivuchakraborty
    https://rivu.dev
    Before We begin

    View Slide

  9. ● Android Developers
    ● Used Kotlin
    ● Loves writing XML?
    ● Used / Loves Declarative UI
    @rivuchakraborty
    https://rivu.dev
    Before We begin

    View Slide

  10. ● Android Developers
    ● Used Kotlin
    ● Loves writing XML?
    ● Used / Loves Declarative UI
    ● Functional / Reactive Programming / Using Redux
    @rivuchakraborty
    https://rivu.dev
    Before We begin

    View Slide

  11. This Talk Covers
    ● Why should we care
    @rivuchakraborty
    https://rivu.dev

    View Slide

  12. @rivuchakraborty
    https://rivu.dev
    This Talk Covers
    ● Why should we care
    ● How to Use Jetpack Compose

    View Slide

  13. @rivuchakraborty
    https://rivu.dev
    This Talk Covers
    ● Why should we care
    ● How to Use Jetpack Compose
    ● How Compose Works

    View Slide

  14. This Talk Covers
    @rivuchakraborty
    https://rivu.dev
    ● Why should we care
    ● How to Use Jetpack Compose
    ● How Compose Works
    ● How to manage States with Compose

    View Slide

  15. @rivuchakraborty
    https://rivu.dev
    Why Should We Care

    View Slide

  16. Why Should We Care
    @rivuchakraborty
    https://rivu.dev

    View Slide

  17. @rivuchakraborty
    https://rivu.dev
    Why Should We Care

    View Slide

  18. @rivuchakraborty
    https://rivu.dev
    Why Should We Care

    View Slide

  19. @rivuchakraborty
    https://rivu.dev
    Why Should We Care

    View Slide

  20. @rivuchakraborty
    https://rivu.dev
    Why Should We Care

    View Slide

  21. Why Should We Care
    @rivuchakraborty
    https://rivu.dev

    View Slide

  22. Why Should We Care
    ● Functional
    ● Declarative
    ● Reactive
    ● UI
    @rivuchakraborty
    https://rivu.dev

    View Slide

  23. Why Should We Care
    @rivuchakraborty
    https://rivu.dev
    Card(color = cardInternalColor) {
    Padding(padding = 12.dp) {
    Column {
    Row {
    ...
    }
    Row {
    ...
    }
    }
    }
    }
    Declarative UI

    View Slide

  24. Why Should We Care
    @rivuchakraborty
    https://rivu.dev
    Declarative UI

    Circular Image
    imageFromResource(
    res = context.resources,
    R.drawable.my_drawable,
    shape = CircleBorder()
    )

    View Slide

  25. Why Should We Care
    ● UI
    ● Declarative
    ● Functional
    ● Reactive
    Functional Declarative UI is on rise to
    become The Way of doing UI
    @rivuchakraborty
    https://rivu.dev

    View Slide

  26. Why Should We Care
    Benefits
    ● Separation of Concerns
    @rivuchakraborty
    https://rivu.dev

    View Slide

  27. Why Should We Care
    Benefits
    ● Separation of Concerns
    ● Declarative + Functional / Reactive
    @rivuchakraborty
    https://rivu.dev

    View Slide

  28. Why Should We Care
    Benefits
    ● Separation of Concerns
    ● Declarative + Functional / Reactive
    ● DSL
    @rivuchakraborty
    https://rivu.dev

    View Slide

  29. Why Should We Care
    Benefits
    ● Separation of Concerns
    ● Declarative + Functional / Reactive
    ● DSL
    ● Developer Friendly
    @rivuchakraborty
    https://rivu.dev

    View Slide

  30. Why Should We Care
    @rivuchakraborty
    https://rivu.dev

    View Slide

  31. Why Should We Care
    Benefits
    ● Flattened UI
    @rivuchakraborty
    https://rivu.dev

    View Slide

  32. Why Should We Care
    Benefits
    ● Flattened UI
    ● Less Compile Time Overhead
    @rivuchakraborty
    https://rivu.dev

    View Slide

  33. Why Should We Care
    Benefits
    ● Flattened UI
    ● Less Compile Time Overhead
    ● Better Performance, Less
    Memory Wastage
    @rivuchakraborty
    https://rivu.dev

    View Slide

  34. Why Should We Care
    Benefits
    ● Flattened UI
    ● Less Compile Time Overhead
    ● Better Performance, Less
    Memory Wastage
    ● Easier State Management
    @rivuchakraborty
    https://rivu.dev

    View Slide

  35. How to use Jetpack
    Compose

    View Slide

  36. How to use
    Jetpack Compose
    Everything is `fun`
    And Lambda

    View Slide

  37. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun CustomText(text: String) {
    Text(text = text, textAlign = TextAlign.Center)
    }

    View Slide

  38. How to use Jetpack Compose
    @Composable
    @rivuchakraborty
    https://rivu.dev

    View Slide

  39. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  40. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun CustomText(text: String) {
    Text(text = text, textAlign = TextAlign.Center)
    }

    View Slide

  41. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    Let’s build a simple
    App

    View Slide

  42. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  43. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    setContent {
    CraneWrapper {
    CustomTheme {
    Counter()
    }
    }
    }

    View Slide

  44. CraneWrapper:
    Needed to buld the
    Foundation
    Might be renamed/removed
    later or get invoked by the
    framework itself inside
    `setContent()`
    How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  45. MaterialTheme /
    CustomTheme: Every Root
    Layout (Anything inside
    CraneWrapper), should have a
    Theme
    How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    setContent {
    CraneWrapper {
    CustomTheme {
    Counter()
    }
    }
    }

    View Slide

  46. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun CustomTheme(children: @Composable() () -> Unit) {
    MaterialTheme(colors=myColorList, typography = myTextStyles) {
    CurrentTextStyleProvider(defaultTextStyle) {
    children()
    }
    }
    }

    View Slide

  47. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    setContent {
    CraneWrapper {
    CustomTheme {
    Counter()
    }
    }
    }

    View Slide

  48. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count 0"
    )
    Button(
    text = "Increase",
    shape = CircleBorder(),
    onClick = {
    //Counter Increment Logic
    }
    )
    }

    View Slide

  49. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count 0"
    )
    Button(
    text = “Increase”,
    shape = CircleBorder(),
    onClick = {
    //Counter Increment Logic
    }
    )
    }

    View Slide

  50. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count 0"
    )
    Button(
    text = "Increase",
    shape = CircleBorder(),
    onClick = {
    //Counter Increment Logic
    }
    )
    }

    View Slide

  51. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count 0"
    )
    Button(
    text = "Increase",
    shape = CircleBorder(),
    onClick = {
    //Counter Increment Logic
    }
    )
    }

    View Slide

  52. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  53. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    Column {
    Row {
    Padding(padding = 5.dp) {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count 0"
    )
    }
    }
    Row {
    Padding(padding = 5.dp) {
    Button(
    text = "Increase",
    onClick = {
    //Counter Increment Logic
    }
    )
    }
    }
    }
    }

    View Slide

  54. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    Column {
    Row {
    Padding(padding = 5.dp) {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count 0"
    )
    }
    }

    View Slide

  55. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    }
    }
    Row {
    Padding(padding = 5.dp) {
    Button(
    text = "Increase",
    onClick = {
    //Counter Increment Logic
    }
    )
    }
    }
    }
    }

    View Slide

  56. @rivuchakraborty
    https://rivu.dev
    How to use Jetpack Compose

    View Slide

  57. Let’s write the logic
    for Counter
    How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  58. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    val countState = +state { 0 }
    Column {
    Row {
    Padding(padding = 5.dp) {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    }
    }
    Row {
    Padding(padding = 5.dp) {
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }
    }
    }
    }

    View Slide

  59. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter() {
    val countState = +state { 0 }
    Column {
    Row {
    Padding(padding = 5.dp) {
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    }
    }
    Row {

    View Slide

  60. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev
    }
    Row {
    Padding(padding = 5.dp) {
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }
    }
    }
    }

    View Slide

  61. How to use Jetpack Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  62. How Compose Works

    View Slide

  63. How Compose Works
    Gap Buffer
    @rivuchakraborty
    https://rivu.dev

    View Slide

  64. Item 1 Item 2 Item 3 Empty Empty Empty Empty
    How Compose Works
    Gap Buffer
    @rivuchakraborty
    https://rivu.dev

    View Slide

  65. How Compose Works
    Gap Buffer Slot Table
    @rivuchakraborty
    https://rivu.dev

    View Slide

  66. How Compose Works
    Slot Table
    Item 1 Item 2 Item 3 Empty Empty Empty Empty
    Cu
    rr
    en
    t
    In
    de
    x
    @rivuchakraborty
    https://rivu.dev

    View Slide

  67. Item 1 Item 2 Item 3 Item 4 Empty Empty Empty
    Cu
    rr
    en
    t
    In
    de
    x
    @rivuchakraborty
    https://rivu.dev
    How Compose Works
    Slot Table

    View Slide

  68. @rivuchakraborty
    https://rivu.dev
    How Compose Works
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  69. Group
    Empty
    Empty
    Empty
    Empty
    Empty
    Empty
    How Compose Works
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  70. Group
    State(0)
    Empty
    Empty
    Empty
    Empty
    Empty
    How Compose Works
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  71. Group
    State(0)
    Group
    Empty
    Empty
    Empty
    Empty
    How Compose Works
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  72. Group
    State(0)
    Group
    “Count 0”
    Empty
    Empty
    Empty
    How Compose Works
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  73. Group
    State(0)
    Group
    “Count 0”
    Group
    Empty
    Empty
    How Compose Works
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  74. Group
    State(0)
    Group
    “Count 0”
    Group
    {...}
    Empty
    How Compose Works
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  75. Group
    State(1)
    Group
    “Count 1”
    Group
    {...}
    Empty
    Recompose How Compose Works
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Counter2() {
    val countState = +state { 0 }
    Text(
    style = +themeTextStyle { h4 },
    text = "Count ${countState.value}"
    )
    Button(
    text = "Increase",
    onClick = {
    countState.value++
    }
    )
    }

    View Slide

  76. View Tree with XML in
    Present Day
    View Group 1
    View
    Group 2
    View
    Group 3
    View
    Group 4
    Image
    View
    Button
    Text
    View
    Toolbar
    @rivuchakraborty
    https://rivu.dev
    How Compose Works

    View Slide

  77. Slot Table
    Group State(1) Group “Count 1” “Group” {...} Empty
    Cu
    rr
    en
    t
    In
    de
    x
    How Compose Works
    @rivuchakraborty
    https://rivu.dev

    View Slide

  78. How to Manage States
    with Compose
    How should we align our thinking
    to work with Functional
    Declarative UIs

    View Slide

  79. How to Manage States with Compose
    State
    View
    Action
    Reactive -
    Redux, Mobx,
    MVI, Mobius,
    MVPI,
    MVVMI ...
    @rivuchakraborty
    https://rivu.dev

    View Slide

  80. State
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    sealed class ViewState: BaseState {
    object Loading: ViewState()
    data class Success(val result: Data): ViewState()
    data class Failure(val error: Throwable): ViewState()
    }

    View Slide

  81. View
    How to Manage States with Compose
    /////MVIActivity.kt
    override fun intents(): Observable {
    ...
    }
    override fun bind() {
    viewModel.processIntents(intents())
    viewModel.states().observe(this,
    Observer {
    ...
    }
    )
    }

    View Slide

  82. ViewModel
    How to Manage States with Compose
    private val intentsSubject: PublishSubject =
    PublishSubject.create()
    val statesObservable: Flowable by lazy {
    intentsSubject
    .map(...)
    ...
    }
    override fun processIntents(intents: Observable) {
    intents.subscribe(intentsSubject)
    }

    View Slide

  83. ViewModel
    How to Manage States with Compose
    ...
    }
    override fun processIntents(intents: Observable) {
    intents.subscribe(intentsSubject)
    }
    override fun states(): LiveData {
    return
    LiveDataReactiveStreams.fromPublisher(statesObservable)
    }

    View Slide

  84. The Problem
    How to Manage States with Compose
    etSearch.addTextChangeListener(object: TextWatcher {
    override fun beforeTextChanged(c:CharSequence, start: Int,
    count: Int, after: Int) {
    ...
    }
    override fun onTextChanged(c:CharSequence, start: Int,
    count: Int, after: Int) {
    ...
    }
    override fun afterTextChanged(s: Editable) {
    ...
    }
    }

    View Slide

  85. Spinner SpinnerAdapter
    OnItemSelectedListener
    How to Manage States with Compose
    The Problem 2
    @rivuchakraborty
    https://rivu.dev

    View Slide

  86. Jetpack
    Compose
    How to Manage States with Compose
    The Solution
    @rivuchakraborty
    https://rivu.dev

    View Slide

  87. Let’s build a
    statefull App
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  88. How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    data class User(
    var name: String="",
    var email: String=""
    )

    View Slide

  89. How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    sealed class UserViewState {
    object Loading: UserViewState()
    data class Success(
    val user: User
    ): UserViewState()
    data class Failure(
    val errorDetails: String
    ): UserViewState()
    }

    View Slide

  90. How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    class UserViewModel: BaseViewModelUserViewState, UserActions, UserResults> {
    override fun states(): LiveData
    }

    View Slide

  91. How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    interface Presenter {
    fun getUserAsync(): Observable
    }

    View Slide

  92. UI
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  93. Success
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Body(user: User, onReloadClick: () -> Unit) {
    Padding(padding = 16.dp) {
    Column {
    Row {
    Text {
    Span(text = "Name: ",style = +themeTextStyle
    { body1 }
    )
    Span(text = user.name, style = +themeTextStyle
    { h6 }
    )
    }
    }

    View Slide

  94. Span(text = user.name, style = +themeTextStyle
    { h6 }
    )
    }
    }
    Row {
    Text {
    Span(text = "Email: ",style = +themeTextStyle
    { body1 }
    )
    Span(text = user.email, style =
    +themeTextStyle { body1 }
    )
    }
    }
    }
    }
    Success
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  95. Span(text = "Email: ",style = +themeTextStyle
    { body1 }
    )
    Span(text = user.email, style =
    +themeTextStyle { body1 }
    )
    }
    }
    }
    }
    Align(Alignment.Center) {
    ReloadButton(onReloadClick)
    }
    }
    Success
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev

    View Slide

  96. Success
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun Body(user: User, onReloadClick: () -> Unit) {
    Padding(padding = 16.dp) {
    Column {
    Row {
    Text {
    Span(text = "Name: ",style = +themeTextStyle { body1 })
    Span(text = user.name, style = +themeTextStyle { h6 })
    }
    }
    Row {
    Text {
    Span(text = "Email: ",style = +themeTextStyle { body1 })
    Span(text = user.email, style = +themeTextStyle { h6 })
    }
    }
    }
    }
    Align(Alignment.Center) {
    ReloadButton(onReloadClick)
    }
    }

    View Slide

  97. Error
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun ErrorBody(onReloadClick: () -> Unit) {
    Align(Alignment.Center) {
    Column {
    Row {
    Text(text = "Load failed", style = +themeTextStyle
    { body1 }
    )
    }
    Row {
    ReloadButton(onReloadClick)
    }
    }
    }
    }

    View Slide

  98. Reload
    Button
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun ReloadButton(onReloadClick: () -> Unit) {
    Button(onClick = onReloadClick,
    text = "Reload",
    color = +themeColor { lightGray })
    }

    View Slide

  99. How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    sealed class UserViewState {
    object Loading: UserViewState()
    data class Success(
    val user: User
    ): UserViewState()
    data class Failure(
    val errorDetails: String
    ): UserViewState()
    }

    View Slide

  100. State change In
    the UI Level
    2 ways
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    sealed class UserViewState {
    object Loading: UserViewState()
    data class Success(
    val user: User
    ): UserViewState()
    data class Failure(
    val errorDetails: String
    ): UserViewState()
    }

    View Slide

  101. Activity
    How to Manage States with Compose
    Approach 1
    @rivuchakraborty
    https://rivu.dev
    class StateExampleActivity : Activity() {
    @Inject
    lateinit var presenter: Presenter
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    CraneWrapper {
    CustomTheme {
    StateComposable(presenter)
    }
    }
    }
    }
    }

    View Slide

  102. Activity
    How to Manage States with Compose
    Approach 1
    @rivuchakraborty
    https://rivu.dev
    class StateExampleActivity : Activity() {
    @Inject
    lateinit var presenter: Presenter
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    CraneWrapper {
    CustomTheme {

    View Slide

  103. lateinit var presenter: Presenter
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    CraneWrapper {
    CustomTheme {
    StateComposable(presenter)
    }
    }
    }
    }
    }
    Activity
    Approach 1
    @rivuchakraborty
    https://rivu.dev

    View Slide

  104. How to Manage States with Compose
    Approach 1
    Root
    Composable
    @rivuchakraborty
    https://rivu.dev
    @Composable
    fun StateComposable(
    presenter: Presenter,
    stateModel: UserViewState = UserViewState.Loading
    ) {
    val data = +state { stateModel }
    fun onReloadClick() {
    data.value = UserViewState.Loading
    }

    View Slide

  105. ) {
    val data = +state { stateModel }
    fun onReloadClick() {
    data.value = UserViewState.Loading
    }
    when (stateModel) {
    is UserViewState.Loading -> {
    +onCommit {
    presenter.getUserAsync()
    .subscribe { userViewState ->
    Approach 1
    Root
    Composable
    @rivuchakraborty
    https://rivu.dev

    View Slide

  106. }
    when (stateModel) {
    is UserViewState.Loading -> {
    +onCommit {
    presenter.getUserAsync()
    .subscribe { userViewState ->
    data.value = userViewState
    }
    }
    Align(Alignment.Center) {
    Text(text = "Loading", style =
    +themeTextStyle { h2 })
    Approach 1
    Root
    Composable
    @rivuchakraborty
    https://rivu.dev

    View Slide

  107. return
    }
    is UserViewState.Failure ->
    ErrorBody(::onReloadClick)
    is UserViewState.Success -> {
    val user = stateModel.user
    Body(user, ::onReloadClick)
    }
    }
    }
    Approach 1
    Root
    Composable
    @rivuchakraborty
    https://rivu.dev

    View Slide

  108. Model Class
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    Approach 2
    @Model
    class ViewStateModel(
    var user: User? = null,
    var error: String = "",
    var isLoading: Boolean = false
    )

    View Slide

  109. Activity
    How to Manage States with Compose
    Approach 2
    @rivuchakraborty
    https://rivu.dev
    class ModelClassExampleActivity : Activity() {
    var stateModel = ViewStateModel(isLoading = true)
    @Inject
    lateinit var presenter: Presenter
    val compositeDisposable = CompositeDisposable()
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    View Slide

  110. val compositeDisposable = CompositeDisposable()
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    CraneWrapper {
    CustomTheme {
    ModelComposable(stateModel,::loadData)
    }
    }
    }
    loadData()
    }
    Activity
    Approach 2
    @rivuchakraborty
    https://rivu.dev

    View Slide

  111. }
    private fun loadData() {
    stateModel.isLoading = true
    val disposable = presenter.getUserAsync()
    .subscribe {
    when (it) {
    is UserViewState.Loading ->
    stateModel.isLoading = true
    is UserViewState.Failure ->
    stateModel.error = it.errorDetails
    is UserViewState.Success ->
    stateModel.user = it.user
    }
    Approach 2
    @rivuchakraborty
    https://rivu.dev
    Activity

    View Slide

  112. }
    compositeDisposable.add(disposable)
    }
    override fun onDestroy() {
    super.onDestroy()
    compositeDisposable.dispose()
    }
    }
    Approach 2
    @rivuchakraborty
    https://rivu.dev
    Activity

    View Slide

  113. Composable
    How to Manage States with Compose
    @rivuchakraborty
    https://rivu.dev
    Approach 2
    @Composable
    fun ModelComposable(viewStateModel: ViewStateModel,
    onReloadClick: () -> Unit) {
    val user = viewStateModel.user
    if(viewStateModel.isLoading) {
    Align(Alignment.Center) {
    Text(text = "Loading", style = +themeTextStyle
    { h2 })
    }
    } else if(viewStateModel.error.isNotBlank() || user ==
    null) {

    View Slide

  114. if(viewStateModel.isLoading) {
    Align(Alignment.Center) {
    Text(text = "Loading", style = +themeTextStyle
    { h2 })
    }
    } else if(viewStateModel.error.isNotBlank() || user ==
    null) {
    ErrorBody(onReloadClick)
    } else {
    Body(user, onReloadClick)
    }
    }
    @rivuchakraborty
    https://rivu.dev

    View Slide

  115. Let’s Talk Composing UI

    Take Aways
    @rivuchakraborty
    https://rivu.dev
    ✓Try out Jetpack Compose
    ✓Play with +state, +model
    ✓Try @Model class
    ✓Try using your preferred Architecture Pattern with Jetpack
    Compose

    View Slide

  116. Let’s Talk Composing UI

    Resources
    ➢ https://developer.android.com/jetpack/compose
    ➢ http://bit.ly/composefirstprinciple
    ➢ http://bit.ly/contentondeclarativeUI
    ➢ https://speakerdeck.com/lelandrichardson/react-meet-compose
    ➢ https://rivu.dev/writing-android-ui-code-in-jetpack-compose/
    ➢ https://rivu.dev/jetpack-compose-managing-states/
    ➢ https://fragmentedpodcast.com/episodes/172/
    @rivuchakraborty
    https://rivu.dev

    View Slide

  117. .droidcon India
    https://in.droidcon.com/

    View Slide

  118. .droidcon India
    https://in.droidcon.com/
    devfestnd

    View Slide

  119. धन्यवाद!! Thank You!!
    @rivuchakraborty
    https://rivu.dev
    Slide Design by instagram.com/mohijeet/

    View Slide