Slide 1

Slide 1 text

Demystifying Jetpack Compose @Linminphyoe1 better.hr

Slide 2

Slide 2 text

What’s in the talk • Old ui toolkit vs Jetpack Compose • Mental model for Jetpack Compose • Inside Jetpack Compose • Using Jetpack Compose

Slide 3

Slide 3 text

Android UI Toolkit Old UI Toolkit vs Jetpack Compose

Slide 4

Slide 4 text

Views

Slide 5

Slide 5 text

Old UI Toolkit - XML

Slide 6

Slide 6 text

Old UI Toolkit - XML

Slide 7

Slide 7 text

Old UI Toolkit - XML

Slide 8

Slide 8 text

Old UI Toolkit — Button public class Button

Slide 9

Slide 9 text

Old UI Toolkit — Button public class Button extends TextView{ ... }

Slide 10

Slide 10 text

Old UI Toolkit — Button public class Button extends TextView{ ... }

Slide 11

Slide 11 text

Old UI Toolkit — Button public class Button extends TextView{ ... } public class TextView extends View{ ... }

Slide 12

Slide 12 text

Old UI Toolkit — LinearLayout public class LinearLayout

Slide 13

Slide 13 text

Old UI Toolkit — LinearLayout public class LinearLayout extends ViewGroup{ ... }

Slide 14

Slide 14 text

Old UI Toolkit — LinearLayout public class LinearLayout extends ViewGroup{ ... }

Slide 15

Slide 15 text

Old UI Toolkit — LinearLayout public class LinearLayout extends ViewGroup{ ... } public class ViewGroup extends View{ ... }

Slide 16

Slide 16 text

So. What’s inside View?? Position Layout Drawing Scrolling Animation Touch Events Focus Handling Size Margin Padding

Slide 17

Slide 17 text

Old UI Toolkit public class Button extends TextView{ ... } public class TextView extends View{ ... } Inheritance

Slide 18

Slide 18 text

Jetpack Compose Declarative, Unbundled UI Toolkit

Slide 19

Slide 19 text

Jetpack Compose •⚠ Pre-alpha currently, API might change • Open-source • API 21+ • Declarative style • Unbundled from OS

Slide 20

Slide 20 text

Functions

Slide 21

Slide 21 text

Clean Code, Page 35 Functions should do one thing. They should do it well. They should do it only. “

Slide 22

Slide 22 text

Composable Functions

Slide 23

Slide 23 text

Composable Functions @Composable fun Button() { ... } @Composable fun Switch() { ... } @Composable fun Row() { Button() Switch() } • Top-level functions • Requires calling context • View tree is created as a result of function call graph

Slide 24

Slide 24 text

Composable Functions @Composable fun Button() { ... }

Slide 25

Slide 25 text

Data flow in Composable Functions @Composable fun Button(text:String) { ... }

Slide 26

Slide 26 text

Data flow in Composable Functions @Composable fun Button(text:String) { ... } Property goes down into function

Slide 27

Slide 27 text

Data flow in Composable Functions @Composable fun Button(text:String) { ... }

Slide 28

Slide 28 text

Data flow in Composable Functions @Composable fun Button(text:String, onClick:(() -> Unit)?) { ... } Event goes up from lamda

Slide 29

Slide 29 text

Data flow in Composable Functions @Composable fun Button(text:String, onClick:(() -> Unit)?) { ... } // Calling side Button(text = "DevFestYangon", onClick = { // Do your actions here })

Slide 30

Slide 30 text

Jetpack Compose vs Old UI Toolkit • Functions over Class • Composition over Inheritance • Feature Composition • UI Library built on top of Kotlin language features

Slide 31

Slide 31 text

Custom views So much easier

Slide 32

Slide 32 text

Creating Date View Dec 7 SAT

Slide 33

Slide 33 text

Creating Date View Dec 7 SAT data class DateUIModel ( val month:String, val date:String, val day: String )

Slide 34

Slide 34 text

@Composable fun DateView(model: DateUIModel) { } data class DateUIModel ( val month:String, val date:String, val day: String ) Dec 7 SAT

Slide 35

Slide 35 text

@Composable fun DateView(model: DateUIModel) { Container(width = 64.dp, height = 64.dp) { } } data class DateUIModel ( val month:String, val date:String, val day: String ) Size of the view Dec 7 SAT It is composable function, too.

Slide 36

Slide 36 text

@Composable fun DateView(model: DateUIModel) { Container(width = 64.dp, height = 64.dp) { } } data class DateUIModel ( val month:String, val date:String, val day: String ) Dec 7 SAT

Slide 37

Slide 37 text

@Composable fun DateView(model: DateUIModel) { Container(width = 64.dp, height = 64.dp) { DrawBorder(border = Border(Color.LightGray, 1.dp), shape = RoundedCornerShape(8.dp)) } } data class DateUIModel ( val month:String, val date:String, val day: String ) Border Dec 7 SAT

Slide 38

Slide 38 text

@Composable fun DateView(model: DateUIModel) { Container(width = 64.dp, height = 64.dp) { DrawBorder(border = Border(Color.LightGray, 1.dp), shape = RoundedCornerShape(8.dp)) } } data class DateUIModel ( val month:String, val date:String, val day: String ) Dec 7 SAT

Slide 39

Slide 39 text

@Composable fun DateView(model: DateUIModel) { Container(width = 64.dp, height = 64.dp) { DrawBorder(border = Border(Color.LightGray, 1.dp), shape = RoundedCornerShape(8.dp)) Column(crossAxisAlignment = CrossAxisAlignment.Center) { Text(model.month) Text(model.date) Text(model.day) } } } data class DateUIModel ( val month:String, val date:String, val day: String ) 3 Texts in a column Dec 7 SAT

Slide 40

Slide 40 text

@Composable fun DateView(model: DateUIModel) { Container(width = 64.dp, height = 64.dp) { DrawBorder(border = Border(Color.LightGray, 1.dp), shape = RoundedCornerShape(8.dp)) Column(crossAxisAlignment = CrossAxisAlignment.Center) { Text(model.month, style = +themeTextStyle { overline }) Text(model.date, style = +themeTextStyle { h6 }) Text(model.day, style = +themeTextStyle { overline }) } } } data class DateUIModel ( val month:String, val date:String, val day: String ) Add styles Dec 7 SAT

Slide 41

Slide 41 text

Using Date View Dec 7 SAT // Model val date = DateUIModel("Dec" , "7" , “SAT") // Create DateView DateView(model = date)

Slide 42

Slide 42 text

Date View Dec 7 SAT // Create DateView DateView(model = date)

Slide 43

Slide 43 text

Date Range View Dec 7 SAT Dec 8 SUN

Slide 44

Slide 44 text

Date Range View Dec 7 SAT Dec 8 SUN @Composable fun DateRangeView(startDate:DateUIModel, endDate:DateUIModel) { }

Slide 45

Slide 45 text

Date Range View Dec 7 SAT Dec 8 SUN @Composable fun DateRangeView(startDate:DateUIModel, endDate:DateUIModel) { Row(crossAxisAlignment = CrossAxisAlignment.Center) { } }

Slide 46

Slide 46 text

Date Range View Dec 7 SAT Dec 8 SUN @Composable fun DateRangeView(startDate:DateUIModel, endDate:DateUIModel) { Row(crossAxisAlignment = CrossAxisAlignment.Center) { DateView(model = startDate) SimpleImage(id = R.drawable.arrow, tint = Color.Gray ) DateView(model = endDate) } }

Slide 47

Slide 47 text

Date Range View Dec 7 SAT Dec 8 SUN @Composable fun DateRangeView(startDate:DateUIModel, endDate:DateUIModel) { Row(crossAxisAlignment = CrossAxisAlignment.Center) { DateView(model = startDate) SimpleImage(id = R.drawable.arrow, tint = Color.Gray ) DateView(model = endDate) } } Start date view needs to be hidden if only end date is provided. How to do it??

Slide 48

Slide 48 text

Date Range View Dec 7 SAT Dec 8 SUN @Composable fun DateRangeView(startDate:DateUIModel?, endDate:DateUIModel) { Row(crossAxisAlignment = CrossAxisAlignment.Center) { startDate?.let{ DateView(model = startDate) SimpleImage(id = R.drawable.arrow, tint = Color.Gray ) } DateView(model = endDate) } } Start date view needs to be hidden if only end date is provided. How to do it??

Slide 49

Slide 49 text

Date Range View Dec 7 SAT Dec 8 SUN @Composable fun DateRangeView(startDate:DateUIModel?, endDate:DateUIModel) { Row(crossAxisAlignment = CrossAxisAlignment.Center) { startDate?.let{ DateView(model = startDate) SimpleImage(id = R.drawable.arrow, tint = Color.Gray ) } DateView(model = endDate) } } Start date view needs to be hidden if only end date is provided. How to do it??

Slide 50

Slide 50 text

Inside Button in Jetpack Compose

Slide 51

Slide 51 text

Button in Jetpack Compose Click Me

Slide 52

Slide 52 text

Click Me @Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface { Ripple { Clickable{ Container { Text(text) } } } } }

Slide 53

Slide 53 text

Click Me @Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface { Ripple { Clickable{ Container { Text(text) } } } } }

Slide 54

Slide 54 text

Click Me @Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface { Ripple { Clickable { Container { Text(text) } } } } }

Slide 55

Slide 55 text

Click Me @Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface { Ripple { Clickable{ Container(constraints = ButtonConstraints, padding = EdgeInsets(8.dp)){ Text(text) } } } } }

Slide 56

Slide 56 text

Click Me @Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface { Ripple { Clickable(onClick = onClick) { Container(constraints = ButtonConstraints, padding = EdgeInsets(8.dp)) { Text(text) } } } } }

Slide 57

Slide 57 text

Click Me @Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface { Ripple(color = Color.Green) { Clickable(onClick = onClick) { Container(constraints = ButtonConstraints, padding = EdgeInsets(8.dp)) { Text(text) } } } } }

Slide 58

Slide 58 text

Click Me @Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface(RoundedCornerShape(4.dp), Color.Red, elevation = 4.dp) { Ripple(color = Color.Green) { Clickable(onClick = onClick) { Container(constraints = ButtonConstraints, padding = EdgeInsets(8.dp)) { Text(text) } } } } }

Slide 59

Slide 59 text

@Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface(RoundedCornerShape(4.dp), Color.Red, elevation = 4.dp) { Ripple(color = Color.Green) { Clickable(onClick = onClick) { Container(constraints = ButtonConstraints, padding = EdgeInsets(8.dp)) { Text(text) } } } } } Click Me Property goes down through functions

Slide 60

Slide 60 text

@Composable fun Button( text: String, onClick: (() -> Unit)? = null ) { Surface(RoundedCornerShape(4.dp), Color.Red, elevation = 4.dp) { Ripple(color = Color.Green) { Clickable(onClick = onClick) { Container(constraints = ButtonConstraints, padding = EdgeInsets(8.dp)) { Text(text) } } } } } Click Me Event go up via lamda

Slide 61

Slide 61 text

Dispatching Composable Function

Slide 62

Slide 62 text

Old Way override fun onCreate(){ setContentView(R.layout.screen_home.xml) } R.layout.screen_home.xml

Slide 63

Slide 63 text

Old Way override fun onCreate(){ setContentView(R.layout.screen_home.xml) } R.layout.screen_home.xml

Slide 64

Slide 64 text

Old Way override fun onCreate(){ setContentView(R.layout.screen_home.xml) } New Way @Composable fun HomeScreen(){ // Your stack of composable views } override fun onCreate(){ setContent { HomeScreen() } } R.layout.screen_home.xml

Slide 65

Slide 65 text

setContent fun Activity.setContent( content: @Composable() () -> Unit ): CompositionContext? { val composeView = window.decorView .findViewById(android.R.id.content) .getChildAt(0) as? AndroidComposeView ?: AndroidComposeView(this).also { setContentView(it) } val coroutineContext = Dispatchers.Main return Compose.composeInto(composeView.root, this) { WrapWithAmbients(composeView, this, coroutineContext) { content() } } }

Slide 66

Slide 66 text

setContent fun Activity.setContent( content: @Composable() () -> Unit ): CompositionContext? { val composeView = window.decorView .findViewById(android.R.id.content) .getChildAt(0) as? AndroidComposeView ?: AndroidComposeView(this).also { setContentView(it) } val coroutineContext = Dispatchers.Main return Compose.composeInto(composeView.root, this) { WrapWithAmbients(composeView, this, coroutineContext) { content() } } }

Slide 67

Slide 67 text

setContent fun Activity.setContent( content: @Composable() () -> Unit ): CompositionContext? { val composeView = window.decorView .findViewById(android.R.id.content) .getChildAt(0) as? AndroidComposeView ?: AndroidComposeView(this).also { setContentView(it) } val coroutineContext = Dispatchers.Main return Compose.composeInto(composeView.root, this) { WrapWithAmbients(composeView, this, coroutineContext) { content() } } }

Slide 68

Slide 68 text

setContent fun Activity.setContent( content: @Composable() () -> Unit ): CompositionContext? { val composeView = window.decorView .findViewById(android.R.id.content) .getChildAt(0) as? AndroidComposeView ?: AndroidComposeView(this).also { setContentView(it) } val coroutineContext = Dispatchers.Main return Compose.composeInto(composeView.root, this) { WrapWithAmbients(composeView, this, coroutineContext) { content() } } }

Slide 69

Slide 69 text

setContent fun ViewGroup.setContent( content: @Composable() () -> Unit ): CompositionContext? { val composeView = if (childCount > 0) { getChildAt(0) as? AndroidComposeView } else { removeAllViews(); null } ?: AndroidComposeView(context).also { addView(it) } val coroutineContext = Dispatchers.Main return Compose.composeInto(composeView.root, context) { WrapWithAmbients(composeView, context, coroutineContext) { content() }

Slide 70

Slide 70 text

setContent fun ViewGroup.setContent( content: @Composable() () -> Unit ): CompositionContext? { val composeView = if (childCount > 0) { getChildAt(0) as? AndroidComposeView } else { removeAllViews(); null } ?: AndroidComposeView(context).also { addView(it) } val coroutineContext = Dispatchers.Main return Compose.composeInto(composeView.root, this) { WrapWithAmbients(composeView, this, coroutineContext) { content() }

Slide 71

Slide 71 text

AndroidComposeView class AndroidComposeView constructor(context: Context) : ViewGroup(context), Owner, DensityScope, SemanticsTreeProvider

Slide 72

Slide 72 text

AndroidComposeView class AndroidComposeView constructor(context: Context) : ViewGroup(context), Owner, DensityScope, SemanticsTreeProvider Element responsible for providing the semantics tree of the hierarchy.

Slide 73

Slide 73 text

Ambients • Composable function that provides data and it can be shared through by whole sub-hierarchy

Slide 74

Slide 74 text

Default Ambients ContextAmbient CoroutineContextAmbient DensityAmbient FocusManagerAmbient TextInputServiceAmbient FontLoaderAmbient AutofillTreeAmbient AutofillAmbient ConfigurationAmbient AndroidComposeViewAmbient LayoutDirectionAmbient

Slide 75

Slide 75 text

Material Theme Ambients @Composable fun MaterialTheme( colors: MaterialColors = MaterialColors(), typography: MaterialTypography = MaterialTypography(), children: @Composable() () -> Unit ) { Colors.Provider(value = colors) { Typography.Provider(value = typography) { CurrentTextStyleProvider(value = typography.body1) { MaterialRippleTheme { MaterialShapeTheme(children = children) } } } } }

Slide 76

Slide 76 text

Ambients @Composable fun MaterialTheme( colors: MaterialColors = MaterialColors(), typography: MaterialTypography = MaterialTypography(), children: @Composable() () -> Unit ) { Colors.Provider(value = colors) { Typography.Provider(value = typography) { CurrentTextStyleProvider(value = typography.body1) { MaterialRippleTheme { MaterialShapeTheme(children = children) } } } } }

Slide 77

Slide 77 text

Getting Ambient values MaterialTheme { // Getting ambient value val primaryColor = +themeColor { primary } }

Slide 78

Slide 78 text

Getting Ambient values MaterialTheme { // Getting ambient value val primaryColor = +themeColor { primary } } MaterialTheme { Row { Card { // Getting ambient value val primaryColor = +themeColor { primary } } } }

Slide 79

Slide 79 text

Using Composable view in old UI Toolkit

Slide 80

Slide 80 text

Using Composable view in old UI Toolkit @Composable fun Greeting(text: String){ Text("Greetings $text") }

Slide 81

Slide 81 text

Using Composable view in old UI Toolkit @Composable @GenerateView fun Greeting(text: String){ Text("Greetings $text") }

Slide 82

Slide 82 text

Using Composable view in old UI Toolkit @Composable @GenerateView fun Greeting(text: String){ Text("Greetings $text") }

Slide 83

Slide 83 text

Using Composable view in old UI Toolkit @Composable @GenerateView fun Greeting(text: String){ Text("Greetings $text") } val greeting:GreetingView = findViewById(R.id.greeting); greeting.setText(“Greetings Compose”);

Slide 84

Slide 84 text

Does Jetpack Compose recompose the whole view tree if something has changed?

Slide 85

Slide 85 text

Positional Memorization

Slide 86

Slide 86 text

Gap Buffer

Slide 87

Slide 87 text

Kotlin Compiler Plugin

Slide 88

Slide 88 text

Recomposition

Slide 89

Slide 89 text

States and Model

Slide 90

Slide 90 text

@Composable fun Counter(){ val count = state { 0 } Button( text = "Count: $count.value", onPress = { count.value += 1 } ) } States and Model

Slide 91

Slide 91 text

States and Model @Composable fun Counter(){ val count = state { 0 } Button( text = "Count: ${count.value}”, onPress = { count.value += 1 } ) }

Slide 92

Slide 92 text

States and Model @Composable fun Counter(){ val count = state { 0 } Button( text = "Count: ${count.value}”, onPress = { count.value += 1 } ) } @Model class State( var value : T )

Slide 93

Slide 93 text

States and Model @Model data class DateUIModel( var month : String, var date : String, var day : String )

Slide 94

Slide 94 text

Try Jetpack Compose • Android Studio 4.0 Canary • https://developer.android.com/jetpack/compose/ setup#sample

Slide 95

Slide 95 text

Jetpack Compose Packages Tooling, Runtime, Compiler

Slide 96

Slide 96 text

Jetpack Compose Packages dependencies { def compose_version = "0.1.0-dev03" // Tooling // e.g. // @Preview for preview in Android Studio // @GenerateView for compatible with current UI Toolkit implementation "androidx.ui:ui-tooling:$compose_version" }

Slide 97

Slide 97 text

Jetpack Compose Packages dependencies { def compose_version = "0.1.0-dev03" // Runtime implementation "androidx.compose:compose-runtime:$compose_version" }

Slide 98

Slide 98 text

dependencies { def compose_version = "0.1.0-dev03" // Framework implementation "androidx.ui:ui-framework:$compose_version" // Layout functions // e.g. Column, Row, Table implementation "androidx.ui:ui-layout:$compose_version" // Material components equivalent implementation "androidx.ui:ui-material:$compose_version" // Foundation functions implementation "androidx.ui:ui-foundation:$compose_version" // Animations and transitions implementation “androidx.ui:ui-animation:$compose_version” } Jetpack Compose Packages

Slide 99

Slide 99 text

Learn • https://developer.android.com/jetpack/compose/ tutorial • https://github.com/Mishkun/jetpack-compose-faq • https://kotlinlang.slack.com/archives/CJLTWPH7S • http://intelligiblebabble.com/compose-from-first- principles/

Slide 100

Slide 100 text

Starting Composing Yours. Thank you ❤ @Linminphyoe1 https://lin.phyo.work https://speakerdeck.com/hashlin Get the slides @

Slide 101

Slide 101 text

@Linminphyoe1 https://lin.phyo.work Take a ride through a Burmese tech scene made by Burmese, for Burmese https://anchor.fm/techshaw @vincentpaing