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

Lifecycles at Scale: with Multiplatform

Dinorah Tovar
July 16, 2024
120

Lifecycles at Scale: with Multiplatform

FLASH NEWS! Kotlin Multiplaform claims another realm - this time focus in Lifecycle!
As Kotlin Multiplatform reach Stable version the time has never been better to understand how Lifecycles works and now that the library has support for it, even better

As we know, all mobile applications has a lifecycle - so let's go in a very deep and fulfilling journey focus on the registry for the lifecycle, the owners and observer and how they get affected using Kotlin Multiplaform and how you can take advantages in all the operating systems, and what does it means having lifecycle libraries as we know for all the other OS that are getting supported

Dinorah Tovar

July 16, 2024
Tweet

Transcript

  1. Lifecycles at Scale: with Multiplatform Dinorah Tovar Google Developer Expert

    Android @ddinorahtovar @ddinorahtovar @ddinorahtovar @ddinorahtovar
  2. This talk has many many many Layers, so please excuse

    me if I jump from topics fast ✨🏃 @ddinorahtovar Many Many Maaaanyyy
  3. Compose But I promise you this topics are related to

    one With a twist 🍋♻🐇 @ddinorahtovar Multiplatform
  4. Compose Is like regular Android Compose but for 🍎🕸🖥 Multiplatform

    @ddinorahtovar @Composable fun Hello() { Text(“Hello") }
  5. @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
  6. Composition & Recomposition is important in Lifecycle First Interaction Composition

    Insert “A” Insert “B” Second Interaction Re-composition @ddinorahtovar
  7. /** * 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<T> constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST") internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State<T> @OptIn(InternalComposeApi::class) inline val current: T @ReadOnlyComposable @Composable get() = currentComposer.consume(this) } @ddinorahtovar
  8. @Stable sealed class CompositionLocal<T> constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST")

    internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State<T> @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 **/
  9. @Stable sealed class CompositionLocal<T> constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST")

    internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State<T> @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 **/
  10. @Stable sealed class CompositionLocal<T> constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST")

    internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State<T> @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 **/
  11. 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) }
  12. 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
  13. To add to CompositionLocal Variables @ddinorahtovar @Composable @OptIn(InternalComposeApi::class) fun CompositionLocalProvider(vararg

    values: ProvidedValue<*>,content: @Composable () -> Unit) { currentComposer.startProviders(values) content() currentComposer.endProviders() }
  14. 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() }
  15. This classs values for the composition three Associates @ddinorahtovar @Stable

    abstract class ProvidableCompositionLocal<T> internal constructor(defaultFactory: () -> T) : CompositionLocal<T> (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) }
  16. @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
  17. @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
  18. LifecycleOwner is over CompositionalLocal “Hosted” @ddinorahtovar @Composable fun SomeComposableFunction ()

    { val lifecycleOwner = LocalLifecycleOwner.current } val LocalLifecycleOwner = staticCompositionLocalOf<LifecycleOwner> { noLocalProvidedFor("LocalLifecycleOwner") }
  19. @Stable sealed class CompositionLocal<T> constructor(defaultFactory: () -> T) { @Suppress("UNCHECKED_CAST")

    internal val defaultValueHolder = LazyValueHolder(defaultFactory) @Composable internal abstract fun provided(value: T): State<T> @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 **/
  20. @ddinorahtovar @Composable fun SomeComposableFunction () { val lifecycleOwner = LocalLifecycleOwner.current

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

    lifecycleOwner.lifecycleScope } LifecycleOwner is over CompositionalLocal “Hosted”
  22. @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
  23. Classes can have Hold on cowboy 🤠 A lifecyle… Well

    no, not exactly, but first a little bit of ✨ context ✨ @ddinorahtovar
  24. @ddinorahtovar Lifecycle dependes🥂 On LifecycleOwner and Lifecycle Lifecycle LifecycleOwner States

    Events OnLifecycleEvent ViewTreeLifecycleOwner ProcessLifecycleOwner
  25. @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
  26. @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
  27. @ddinorahtovar Created Started Events and States Resumed Paused Stoped Destroyed

    onCreate() onStart() onResume() onPause() onStop() onDestroy()
  28. 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 } }
  29. Once this class is created you can In ApplicationClass Attach

    @ddinorahtovar ProcessLifecycleOwner.get() .lifecycle.addObserver(AppOwner())
  30. LifecycleOwner Lifecycle depends on MORE things such as the classes

    A lifecyle… kinda, but first more ✨ context ✨ @ddinorahtovar
  31. @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
  32. 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
  33. iOS and Web I lie to you… cause this talk

    also includes Cause they have lifecycles too ✨🎉👩💻👩🎨🏹 @ddinorahtovar
  34. @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
  35. Compose Finally, at the end It shows how finally we

    could generalize lifecycle managed on both Android, Web & iOS 🍋♻🐇 @ddinorahtovar Multiplatform
  36. Lifecycles at Scale: with Multiplatform Dinorah Tovar Google Developer Expert

    Android @ddinorahtovar @ddinorahtovar @ddinorahtovar @ddinorahtovar