Slide 1

Slide 1 text

This work is licensed under the Apache 2.0 License State and Theming in Jetpack Compose Pathway 1-2

Slide 2

Slide 2 text

Speaker skydoves @github_skydoves Android Developer Advocate @ Stream 엄재웅 (Jaewoong Eum)

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Codelab Guidelines

Slide 5

Slide 5 text

This work is licensed under the Apache 2.0 License https://github.com/gdgand/ComposeCamp2022 Codelab Guidelines Fork the project on GitHub

Slide 6

Slide 6 text

This work is licensed under the Apache 2.0 License Codelab Guidelines ● Clone the project ● Checkout to a new branch

Slide 7

Slide 7 text

Compose Phases

Slide 8

Slide 8 text

This work is licensed under the Apache 2.0 License Compose Phases Which UI to draw Where to place UI. Measurement and placement How it renders

Slide 9

Slide 9 text

This work is licensed under the Apache 2.0 License Recomposition Update UI (Click the Checkbox)

Slide 10

Slide 10 text

This work is licensed under the Apache 2.0 License @Composable private fun WellnessTaskItem(..) { Text() Checkbox() IconButton() } Recomposition

Slide 11

Slide 11 text

This work is licensed under the Apache 2.0 License Recomposition @Composable private fun WellnessTaskItem(..) { Text() Checkbox() IconButton() } Update UI (Click the Checkbox) @Composable private fun WellnessTaskItem(..) { Text() Checkbox() IconButton() } Recomposition

Slide 12

Slide 12 text

This work is licensed under the Apache 2.0 License Recomposition @Composable private fun WellnessTaskItem(..) { Text() Checkbox() IconButton() } Smart Recomposition Update UI (Click the Checkbox) @Composable private fun WellnessTaskItem(..) { Text() Checkbox() IconButton() } Skip Skip Recomposition

Slide 13

Slide 13 text

This work is licensed under the Apache 2.0 License Recomposition and Performance https://getstream.io/blog/jetpack-compose-guidelines/ https://youtu.be/EOQB8PTLkpY

Slide 14

Slide 14 text

State in Compose

Slide 15

Slide 15 text

This work is licensed under the Apache 2.0 License What's the State? State An interface that has a value property during the execution of a Composable function. MutableState A mutable value holder where reads to the value property during the execution of a Composable function. Any changes to value will schedule recomposition of any composable functions that read value.

Slide 16

Slide 16 text

This work is licensed under the Apache 2.0 License State and Recomposition Composition Display UI User Event Update State @Composable

Slide 17

Slide 17 text

This work is licensed under the Apache 2.0 License State and Recomposition Composition Display UI User Event Update State @Composable

Slide 18

Slide 18 text

This work is licensed under the Apache 2.0 License State and Recomposition Composition Display UI User Event Update State @Composable

Slide 19

Slide 19 text

This work is licensed under the Apache 2.0 License State and Recomposition Composition Updated UI User Event Update State Recomposition @Composable

Slide 20

Slide 20 text

This work is licensed under the Apache 2.0 License What's the State? Value Holder A value holder where reads to the value property during the execution of a Composable function. Recomposition Trigger When the value property is written to and changed, recomposition of any subscribed Recompose scopes will be scheduled. Observable The current Recompose scope will observe states and be subscribed to changes of that value.

Slide 21

Slide 21 text

This work is licensed under the Apache 2.0 License State in Composable @Composable fun WaterCounter(modifier: Modifier = Modifier) { Column(modifier = modifier.padding(16.dp)) { // Changes to count are now tracked by Compose val count: MutableState = mutableStateOf(0) Text("You've had ${count.value} glasses.") Button(onClick = { count.value++ }, Modifier.padding(top = 8.dp)) { Text("Add one") } } }

Slide 22

Slide 22 text

This work is licensed under the Apache 2.0 License @Composable fun WaterCounter(modifier: Modifier = Modifier) { Column(modifier = modifier.padding(16.dp)) { // Changes to count are now tracked by Compose val count: MutableState = mutableStateOf(0) Text("You've had ${count.value} glasses.") Button(onClick = { count.value++ }, Modifier.padding(top = 8.dp)) { Text("Add one") } } } State in Composable Compilation error!

Slide 23

Slide 23 text

This work is licensed under the Apache 2.0 License State in Composable @Composable fun WaterCounter(modifier: Modifier = Modifier) { val count: MutableState = mutableStateOf(0) .. } Initialize states

Slide 24

Slide 24 text

This work is licensed under the Apache 2.0 License @Composable fun WaterCounter(modifier: Modifier = Modifier) { Column(modifier = modifier.padding(16.dp)) { var count by remember { mutableStateOf(0) } Text("You've had $count glasses.") Button(onClick = { count++ }, Modifier.padding(top = 8.dp)) { Text("Add one") } } } State and Remember Remember Composable functions can use the remember API to store an object in memory.

Slide 25

Slide 25 text

This work is licensed under the Apache 2.0 License RemeberSaveable @Composable fun WaterCounter(modifier: Modifier = Modifier) { val count: MutableState by rememberSaveable { mutableStateOf(0) } .. } RememberSaveable It behaves similarly to remember, but the stored value will survive the activity or process recreation using the saved instance state mechanism. ● Configuration changes ● Switch between dark and light mode ● Change language settings

Slide 26

Slide 26 text

This work is licensed under the Apache 2.0 License Remember and Recomposition @Composable fun ContactList( contacts: List, comparator: Comparator ) { LazyColumn(Modifier) { items(contacts.sortedWith(comparator)) { contact -> // ... } } }

Slide 27

Slide 27 text

This work is licensed under the Apache 2.0 License Remember and Recomposition @Composable fun ContactList( contacts: List, comparator: Comparator ) { LazyColumn(Modifier) { // DON'T DO THIS items(contacts.sortedWith(comparator)) { contact -> // ... } } }

Slide 28

Slide 28 text

This work is licensed under the Apache 2.0 License Remember and Recomposition @Composable fun ContactList( contacts: List, comparator: Comparator, ) { val sortedContacts = remember(contacts, sortComparator) { contacts.sortedWith(sortComparator) } LazyColumn { items(sortedContacts) { // ... } …

Slide 29

Slide 29 text

This work is licensed under the Apache 2.0 License Stateful vs Stateless @Composable fun WaterCounter(modifier: Modifier = Modifier) { val count: MutableState by remember { mutableStateOf(0) } .. } Stateful

Slide 30

Slide 30 text

This work is licensed under the Apache 2.0 License Stateful vs Stateless @Composable fun WaterCounter(modifier: Modifier = Modifier) { val count: MutableState by remember { mutableStateOf(0) } .. } @Composable fun WaterCounter( modifier: Modifier = Modifier, count: Int = 0 ) { ... } Stateful Stateless

Slide 31

Slide 31 text

This work is licensed under the Apache 2.0 License Why Stateless? Single source of truth By moving state instead of duplicating it, we're ensuring there's only one source of truth. This helps avoid bugs. Decoupled The state for the stateless Composable may be stored anywhere. It increases the reusability of the stateless Composable. Encapsulated Only stateful composables will be able to modify their state. It's completely internal.

Slide 32

Slide 32 text

This work is licensed under the Apache 2.0 License State Hoisting @Composable fun WaterCounter(modifier: Modifier = Modifier) { Column(modifier = modifier.padding(16.dp)) { var count by remember { mutableStateOf(0) } Text("You've had $count glasses.") Button(onClick = { count++ }, Modifier.padding(top = 8.dp)) { Text("Add one") } } }

Slide 33

Slide 33 text

This work is licensed under the Apache 2.0 License State Hoisting @Composable fun WaterCounter(modifier: Modifier = Modifier) { Column(modifier = modifier.padding(16.dp)) { var count by remember { mutableStateOf(0) } Text("You've had $count glasses.") Button(onClick = { count++ }, Modifier.padding(top = 8.dp)) { Text("Add one") } } } State Read state Write state

Slide 34

Slide 34 text

This work is licensed under the Apache 2.0 License State Hoisting @Composable fun WaterCounter(modifier: Modifier = Modifier) { Column(modifier = modifier.padding(16.dp)) { var count by remember { mutableStateOf(0) } Text("You've had $count glasses.") Button(onClick = { count++ }, Modifier.padding(top = 8.dp)) { Text("Add one") } } } @Composable fun StatelessCounter( count: Int, onIncrement: () -> Unit, modifier: Modifier = Modifier ) { Column(modifier = modifier.padding(16.dp)) { Text("You've had $count glasses.") Button(onClick = onIncrement, Modifier.padding(top = 8.dp)) { Text("Add one") } } }

Slide 35

Slide 35 text

This work is licensed under the Apache 2.0 License State Hoisting @Composable fun StatefulCounter() { var waterCount by remember { mutableStateOf(0) } StatelessCounter(waterCount, { waterCount++ }) } State State @Composable fun StatelessCounter(count: Int, onIncrement: () -> Unit) { Text("You've had $count glasses.") Button(onClick = onIncrement, Modifier.padding(top = 8.dp)) { .. } Stateful Stateless

Slide 36

Slide 36 text

CompositionLocal

Slide 37

Slide 37 text

This work is licensed under the Apache 2.0 License CompositionLocal Composable A Composable B Composable C @Composable fun ComposableA() { ComposableB(Color.White) } @Composable fun ComposableB(color: Color) { ComposableC(Color.White) } @Composable fun ComposableC(color: Color) { .. }

Slide 38

Slide 38 text

This work is licensed under the Apache 2.0 License CompositionLocal Composable A Composable B Composable C @Composable fun ComposableA() { ComposableB(Color.White) } @Composable fun ComposableB(color: Color) { ComposableC(Color.White) } @Composable fun ComposableC(color: Color) { .. }

Slide 39

Slide 39 text

This work is licensed under the Apache 2.0 License CompositionLocal Composable A Composable B Composable C @Composable fun ComposableA() { ComposableB(Color.White) } @Composable fun ComposableB(color: Color) { ComposableC(Color.White) } @Composable fun ComposableC(color: Color) { .. } Dependency

Slide 40

Slide 40 text

This work is licensed under the Apache 2.0 License CompositionLocal Composable A Composable B Composable C @Composable fun ComposableA() { CompositionLocalProvider(LocalColor provides color) { .. } @Composable fun ComposableB() { ComposableC() } @Composable fun ComposableC() { val color = LocalColor.current }

Slide 41

Slide 41 text

This work is licensed under the Apache 2.0 License CompositionLocal By Elye

Slide 42

Slide 42 text

This work is licensed under the Apache 2.0 License CompositionLocal https://developer.android.com/jetpack/compose/compositionlocal val ColorCompositionLocal = staticCompositionLocalOf { error("No Color provided") } CompositionLocalProvider(ColorCompositionLocal provides color) { MyComposableFunction(...) } @Composable fun MyComposableFunction() { val color = ColorCompositionLocal.current }

Slide 43

Slide 43 text

Compose Theming

Slide 44

Slide 44 text

This work is licensed under the Apache 2.0 License Material Design

Slide 45

Slide 45 text

This work is licensed under the Apache 2.0 License Material Design in Compose Color Typography Shape

Slide 46

Slide 46 text

This work is licensed under the Apache 2.0 License MaterialTheme @Composable fun JetnewsTheme(content: @Composable () -> Unit) { MaterialTheme( colorScheme = myColorScheme, shapes = MyShapes, typography = MyTypography, content = content ) }

Slide 47

Slide 47 text

This work is licensed under the Apache 2.0 License MaterialTheme @Composable fun MaterialTheme(..) { CompositionLocalProvider( LocalColorScheme provides rememberedColorScheme, LocalIndication provides rippleIndication, LocalRippleTheme provides MaterialRippleTheme, LocalShapes provides shapes, LocalTextSelectionColors provides selectionColors, LocalTypography provides typography, ) { ProvideTextStyle(value = typography.bodyLarge, content = content) } }

Slide 48

Slide 48 text

This work is licensed under the Apache 2.0 License MaterialTheme @Composable fun MyMaterialTheme(..) { val isDarkTheme = isSystemInDarkTheme() val colorScheme = if (isDarkTheme) { darkColorSceme } else { lightColorSceme } MaterialTheme(colorScheme = colorScheme) { MyScreen() } }

Slide 49

Slide 49 text

Thank you! This work is licensed under the Apache 2.0 License