Slide 1

Slide 1 text

Lifecycles at Scale: with Multiplatform Dinorah Tovar Google Developer Expert Android @ddinorahtovar @ddinorahtovar @ddinorahtovar @ddinorahtovar

Slide 2

Slide 2 text

This talk has many many many Layers, so please excuse me if I jump from topics fast ✨🏃 @ddinorahtovar Many Many Maaaanyyy

Slide 3

Slide 3 text

Compose But I promise you this topics are related to one With a twist 🍋♻🐇 @ddinorahtovar Multiplatform

Slide 4

Slide 4 text

@ddinorahtovar A little bit of Before we start, this talk is needs ✨ context ✨

Slide 5

Slide 5 text

@ddinorahtovar

Slide 6

Slide 6 text

Compose Multiplatform First: Just a quick stop here 🛑✨ @ddinorahtovar

Slide 7

Slide 7 text

Compose Is like regular Android Compose but for 🍎🕸🖥 Multiplatform @ddinorahtovar @Composable fun Hello() { Text(“Hello") }

Slide 8

Slide 8 text

@ddinorahtovar As Kotlin Multiplatform Compose Multiplatform Is not a hard compromise

Slide 9

Slide 9 text

@ddinorahtovar Web Kotlin/WASM What it means for every platform WebAssembly DOM support Alpha iOS Kotlin Native Swift Framework Objective-C Framework Safari support WIP Desktop Kotlin/JVM Beta

Slide 10

Slide 10 text

Compose fuctions Second Has lifecycle ♻… well kinda @ddinorahtovar

Slide 11

Slide 11 text

Composition & Recomposition is important in Lifecycle First Interaction Composition Insert “A” Insert “B” Second Interaction Re-composition @ddinorahtovar

Slide 12

Slide 12 text

/** * A common LifecycleOwner * provides a lifecycle for * all interconnected * entities * * In Multiplatform all * composable share the same * lifecycle and can listen * changes **/ @Stable sealed class CompositionLocal constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST") internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State @OptIn(InternalComposeApi::class) inline val current: T @ReadOnlyComposable @Composable get() = currentComposer.consume(this) } @ddinorahtovar

Slide 13

Slide 13 text

@Stable sealed class CompositionLocal constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST") internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State @OptIn(InternalComposeApi::class) inline val current: T @ReadOnlyComposable @Composable get() = currentComposer.consume(this) } @ddinorahtovar /** * A common LifecycleOwner * provides a lifecycle for * all interconnected * entities * * In Multiplatform all * composable share the same * lifecycle and can listen * changes **/

Slide 14

Slide 14 text

@Stable sealed class CompositionLocal constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST") internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State @OptIn(InternalComposeApi::class) inline val current: T @ReadOnlyComposable @Composable get() = currentComposer.consume(this) } @ddinorahtovar /** * A common LifecycleOwner * provides a lifecycle for * all interconnected * entities * * In Multiplatform all * composable share the same * lifecycle and can listen * changes **/

Slide 15

Slide 15 text

@Stable sealed class CompositionLocal constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST") internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State @OptIn(InternalComposeApi::class) inline val current: T @ReadOnlyComposable @Composable get() = currentComposer.consume(this) } @ddinorahtovar /** * A common LifecycleOwner * provides a lifecycle for * all interconnected * entities * * In Multiplatform all * composable share the same * lifecycle and can listen * changes **/

Slide 16

Slide 16 text

CompositionLocal To CompositionLocal Key, Value @ddinorahtovar 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 17

Slide 17 text

A pair of To CompositionLocalProvider Key, Value @ddinorahtovar 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) } Key Value

Slide 18

Slide 18 text

To add to CompositionLocal Variables @ddinorahtovar @Composable @OptIn(InternalComposeApi::class) fun CompositionLocalProvider(vararg values: ProvidedValue<*>,content: @Composable () -> Unit) { currentComposer.startProviders(values) content() currentComposer.endProviders() }

Slide 19

Slide 19 text

CompositionLocalProvider Values for the three Binds @ddinorahtovar @Composable @OptIn(InternalComposeApi::class) fun CompositionLocalProvider(vararg values: ProvidedValue<*>,content: @Composable () -> Unit) { currentComposer.startProviders(values) content() currentComposer.endProviders() }

Slide 20

Slide 20 text

This classs values for the composition three Associates @ddinorahtovar @Stable abstract class ProvidableCompositionLocal internal constructor(defaultFactory: () -> T) : CompositionLocal (defaultFactory) { @Suppress("UNCHECKED_CAST") infix fun provides(value: T) = ProvidedValue(this, value, true) @Suppress("UNCHECKED_CAST") infix fun providesDefault(value: T) = ProvidedValue(this, value, false) }

Slide 21

Slide 21 text

@ddinorahtovar You can make your own theme or use the MaterialTheme Column LazyColumn Rows Text Root SomeTheme CompositionLocalProvider A clear example With a Theme for Compose

Slide 22

Slide 22 text

@Composable fun DesignTheme( colors: DesignColorPalette = lightColorPalette(), children: @Composable() () -> Unit ) { CompositionLocalProvider( LocalDlsColors provides colors, ) { MaterialTheme( colors = colors.materialColors ) { children() } } } object DesignTheme { val colors: DesignColorPalette @Composable @ReadOnlyComposable get() = LocalDlsColors.current } internal val LocalDlsColors = staticCompositionLocalOf { lightColorPalette() } /** * As we use * CompositionLocal * to create themes, and * make available the colors * we can do it for * Lifecycle **/ @ddinorahtovar

Slide 23

Slide 23 text

@ddinorahtovar If you wanna see more about Custom designs themes @rharte on #ChicagoRoboto

Slide 24

Slide 24 text

@ddinorahtovar If you wanna know more about Design Systems using Material Design You can see mine :)

Slide 25

Slide 25 text

LifecycleOwner is over CompositionalLocal “Hosted” @ddinorahtovar @Composable fun SomeComposableFunction () { val lifecycleOwner = LocalLifecycleOwner.current } val LocalLifecycleOwner = staticCompositionLocalOf { noLocalProvidedFor("LocalLifecycleOwner") }

Slide 26

Slide 26 text

@Stable sealed class CompositionLocal constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST") internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State @OptIn(InternalComposeApi::class) inline val current: T @ReadOnlyComposable @Composable get() = currentComposer.consume(this) } @ddinorahtovar /** * A common LifecycleOwner * provides a lifecycle for * all interconnected * entities * * In Multiplatform all * composable share the same * lifecycle and can listen * changes **/

Slide 27

Slide 27 text

@ddinorahtovar @Composable fun SomeComposableFunction () { val lifecycleOwner = LocalLifecycleOwner.current } val LocalLifecycleOwner = staticCompositionLocalOf { noLocalProvidedFor("LocalLifecycleOwner") } LifecycleOwner is over CompositionalLocal “Hosted”

Slide 28

Slide 28 text

@ddinorahtovar @Composable fun SomeComposableFunction () { val lifecycleOwner = LocalLifecycleOwner.current lifecycleOwner.lifecycleScope } LifecycleOwner is over CompositionalLocal “Hosted”

Slide 29

Slide 29 text

@ddinorahtovar public interface LifecycleOwner { public val lifecycle: Lifecycle } public val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope get() = lifecycle.coroutineScope LifecycleOwner holds On Android and a little scope Lifecycle

Slide 30

Slide 30 text

Lifecycle Third Is 🦆 complex @ddinorahtovar

Slide 31

Slide 31 text

Lifecycle on Android @ddinorahtovar General Application Activity Fragment Composables Classes*

Slide 32

Slide 32 text

Classes can have Hold on cowboy 🤠 A lifecyle… Well no, not exactly, but first a little bit of ✨ context ✨ @ddinorahtovar

Slide 33

Slide 33 text

@ddinorahtovar Lifecycle dependes🥂 On LifecycleOwner and Lifecycle Lifecycle LifecycleOwner States Events OnLifecycleEvent ViewTreeLifecycleOwner ProcessLifecycleOwner

Slide 34

Slide 34 text

@ddinorahtovar Lifecycle dependes🥂 States are stages in the graph Lifecycle Operation For States DESTROYED, INITIALIZED, CREATED, RESUMED, STARTED Creates, initialize and destroy all the stages over the lifecycle

Slide 35

Slide 35 text

@ddinorahtovar Lifecycle dependes🥂 Events are edges between the Stages Lifecycle Operation For Events ON_CREATE, ON_STARTED, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY, ON_ANY Creates initialize and destroy all the stages over the lifecycle

Slide 36

Slide 36 text

@ddinorahtovar Created Started Events and States Resumed Paused Stoped Destroyed onCreate() onStart() onResume() onPause() onStop() onDestroy()

Slide 37

Slide 37 text

Events can be On regular clasess Used @ddinorahtovar class AppOwner : DefaultLifecycleObserver { override fun onStart(owner: LifecycleOwner) { super.onStart(owner) // App was resumed or started } override fun onPause(owner: LifecycleOwner) { super.onPause(owner) // App has been moved to background // includes switch to other app // includes just moving to task manager } }

Slide 38

Slide 38 text

Once this class is created you can In ApplicationClass Attach @ddinorahtovar ProcessLifecycleOwner.get() .lifecycle.addObserver(AppOwner())

Slide 39

Slide 39 text

LifecycleOwner Lifecycle depends on MORE things such as the classes A lifecyle… kinda, but first more ✨ context ✨ @ddinorahtovar

Slide 40

Slide 40 text

@ddinorahtovar Owners Fragment 
 Initialize lifecycle Set View - to ViewThreeLifecycleOwner FragmentView LifecycleOwner 
 Init of LifecycleRegistry Repo rt lifecycle of view Set View - to ViewThreeViewModelStoreOw Set View - to ViewThreeSavedStateRegistry Repo rt accessors of SavedStateRegistryOwner Repo rt s accessors of ViewModelStoreOwner

Slide 41

Slide 41 text

Left Aligned Title @ddinorahtovar /** * Handle observers - addObserver() * Used on Fragments and Activities * Handle and dispatch events around the process of the activity and fragment **/ LifecycleRegistry

Slide 42

Slide 42 text

Lifecycle Four Are everywhere ✨🙆 @ddinorahtovar

Slide 43

Slide 43 text

iOS and Web I lie to you… cause this talk also includes Cause they have lifecycles too ✨🎉👩💻👩🎨🏹 @ddinorahtovar

Slide 44

Slide 44 text

@ddinorahtovar iOS Lifecycle

Slide 45

Slide 45 text

@ddinorahtovar iOS Lifecycle

Slide 46

Slide 46 text

@ddinorahtovar iOS Lifecycle OnStart OnResume OnStop

Slide 47

Slide 47 text

@ddinorahtovar Lifecycle Events on iOS 🥂 iOS Lifecycles Lifecycle event For viewDidDisappear - viewcontroller ON_STOP STARTED → CREATED viewWillAppear - viewcontroller ON_START CREATED → STARTED willResignActive - app ON_PAUSE RESUMED → STARTED didBecomeActive - app ON_RESUME STARTED → RESUMED didEnterBackground - app ON_STOP STARTED → CREATED willEnterForeground - app ON_START CREATED → STARTED

Slide 48

Slide 48 text

Compose Finally, at the end It shows how finally we could generalize lifecycle managed on both Android, Web & iOS 🍋♻🐇 @ddinorahtovar Multiplatform

Slide 49

Slide 49 text

Lifecycles at Scale: with Multiplatform Dinorah Tovar Google Developer Expert Android @ddinorahtovar @ddinorahtovar @ddinorahtovar @ddinorahtovar