Slide 1

Slide 1 text

Webuni webinar – @stewemetal stewemetal The Future of Android Development István Juhos Jetpack Compose

Slide 2

Slide 2 text

Webuni webinar – @stewemetal How we write UI now? • View objects inflated from XML layout files • For more than 10 years now 🗓

Slide 3

Slide 3 text

Webuni webinar – @stewemetal How we write UI now? • View objects inflated from XML layout files • For more than 10 years now 🗓 • Tons and tons of other UI-related XMLs • Drawables/colors + selectors • Themes + styles • Custom styling attributes

Slide 4

Slide 4 text

Webuni webinar – @stewemetal How we write UI now? • View objects inflated from XML layout files • For more than 10 years now 🗓 • Tons and tons of other UI-related XMLs • Drawables/colors + selectors • Themes + styles • Custom styling attributes • View Binding / Data Binding • Code generation and a pinch of pixie dust… ✨ • @BindingAdapters

Slide 5

Slide 5 text

Webuni webinar – @stewemetal Imperative 👑

Slide 6

Slide 6 text

Webuni webinar – @stewemetal Imperative 👑 “Imperative programming focuses on describing how a program operates step by step, rather than on high-level descriptions of its expected results.” - Wikipedia

Slide 7

Slide 7 text

Webuni webinar – @stewemetal Imperative 👑 • Objects created exactly how we declare them inflate

Slide 8

Slide 8 text

Webuni webinar – @stewemetal Declarative 📣 The Future (is now!)

Slide 9

Slide 9 text

Webuni webinar – @stewemetal Declarative 📣 • ❌ Writing how the UI should be built • ✅ Writing what the UI should look like, and let the framework figure out how to achieve the result ConstraintLayout( modifier = Modifier .background(MaterialTheme.colors.background) .height(60.dp) .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), ) { Text( text = item.text, color = Grey, ) Icon( painterResource(id = drawable.ic_chevron_right), ) } * Not actual working code! *

Slide 10

Slide 10 text

Webuni webinar – @stewemetal What is Compose?

Slide 11

Slide 11 text

Webuni webinar – @stewemetal What is Compose? • A general-purpose, multiplatform compiler and runtime for managing a tree of nodes of any type https://jakewharton.com/a-jetpack-compose-by-any-other-name/

Slide 12

Slide 12 text

Webuni webinar – @stewemetal What is Compose? • A general-purpose, multiplatform compiler and runtime for managing a tree of nodes of any type AND ALSO • A UI toolkit and DSL to render app UI on Android and Desktop https://jakewharton.com/a-jetpack-compose-by-any-other-name/

Slide 13

Slide 13 text

Webuni webinar – @stewemetal What is Compose UI? • Declarative • Like React (Native), Flutter, and SwiftUI • Component-based • Unbundled • Kotlin-only • The UI is a function of the current UI state

Slide 14

Slide 14 text

Webuni webinar – @stewemetal • Declarative • Like React (Native), Flutter, and SwiftUI • Component-based • Unbundled • Kotlin-only • The UI is a function of the current UI state f(state) UI = What is Compose UI?

Slide 15

Slide 15 text

Webuni webinar – @stewemetal • We can use Composable functions to describe UI components based on the current UI state • Two-way interoperability • Works with existing View-based UI and vice versa • AndroidView composable for Views in Compose • ComposeView for Composables in Views What is Compose UI? f(state) UI =

Slide 16

Slide 16 text

Webuni webinar – @stewemetal A simple list – View vs. Compose Check out the first demo project here: https://github.com/stewemetal/android-view-vs-compose

Slide 17

Slide 17 text

Webuni webinar – @stewemetal A simple list – Android View

Slide 18

Slide 18 text

Webuni webinar – @stewemetal A simple list – Android View ConstraintLayout

Slide 19

Slide 19 text

Webuni webinar – @stewemetal A simple list – Android View MaterialToolbar RecyclerView

Slide 20

Slide 20 text

Webuni webinar – @stewemetal A simple list – Android View List item view… List item view…

Slide 21

Slide 21 text

Webuni webinar – @stewemetal A simple list – Android View List item view

Slide 22

Slide 22 text

Webuni webinar – @stewemetal A simple list – Android View Layout of a Fragment - fragment_view.xml

Slide 23

Slide 23 text

Webuni webinar – @stewemetal A simple list – Android View Fragment - ViewFragment.kt class ViewFragment : Fragment() { lateinit var adapter: ViewItemAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View = inflater.inflate(R.layout.fragment_view, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) adapter = ViewItemAdapter() val list = view.findViewById(R.id.list) list.adapter = adapter adapter.submitList( mutableListOf().apply { (1..30).forEach { add(Item("View item $it")) } } ) } }

Slide 24

Slide 24 text

Webuni webinar – @stewemetal A simple list – Android View Adapter - ViewItemAdapter.kt class ViewItemAdapter : ListAdapter(ItemDiffUtil()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder = ItemViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.layout_item, parent, false) ) override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { holder.bind(getItem(position)) } inner class ItemViewHolder(itemView: View) : ViewHolder(itemView) { private val itemText: TextView = itemView.findViewById(R.id.itemText) fun bind(item: Item) { itemText.text = item.text } } } class ItemDiffUtil : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean { return oldItem == newItem } override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean { return oldItem == newItem } }

Slide 25

Slide 25 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose

Slide 26

Slide 26 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose

Slide 27

Slide 27 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose ComposeView (interoperability)

Slide 28

Slide 28 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose Composable Composable Composable

Slide 29

Slide 29 text

Webuni webinar – @stewemetal Interoperability - fragment_compose.xml A simple list – Jetpack Compose

Slide 30

Slide 30 text

Webuni webinar – @stewemetal Interoperability - fragment_compose.xml A simple list – Jetpack Compose Interoperability with Views

Slide 31

Slide 31 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose List item composable - ListItem.kt } @Composable fun ListItem( item: Item, ) { // ...

Slide 32

Slide 32 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose List item composable - ListItem.kt @Composable fun ListItem( item: Item, ) { // ... } @Composable fun ListItem( ) f()

Slide 33

Slide 33 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose List item composable - ListItem.kt } @Composable fun ListItem( item: Item, ) { // ... f(state) @Composable fun ListItem( item: Item, ) { // ... }

Slide 34

Slide 34 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose List item composable - ListItem.kt @Composable fun ListItem( item: Item, ) { // ... } f(state) UI = @Composable fun ListItem( item: Item, ) { // ... }

Slide 35

Slide 35 text

Webuni webinar – @stewemetal A simple list – Jetpack Compose List item composable - ListItem.kt } @Composable fun ListItem( item: Item, ) { // ...

Slide 36

Slide 36 text

Webuni webinar – @stewemetal @Composable fun ListItem( item: Item, ) { ConstraintLayout( modifier = Modifier .background(MaterialTheme.colors.background) .height(60.dp) .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), ) { // ... } A simple list – Jetpack Compose List item composable - ListItem.kt

Slide 37

Slide 37 text

Webuni webinar – @stewemetal @Composable fun ListItem( item: Item, ) { ConstraintLayout( modifier = Modifier .background(MaterialTheme.colors.background) .height(60.dp) .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), ) { val (text, chevron) = createRefs() Text( text = item.text, color = Grey, fontSize = 16.sp, modifier = Modifier .constrainAs(text) { top.linkTo(parent.top) start.linkTo(parent.start) end.linkTo(chevron.start) bottom.linkTo(parent.bottom) width = Dimension.fillToConstraints }, ) Icon( painterResource(id = drawable.ic_chevron_right), tint = Grey, contentDescription = "Item arrow forward", modifier = Modifier .constrainAs(chevron) { top.linkTo(parent.top) start.linkTo(text.end, margin = 16.dp) end.linkTo(parent.end) bottom.linkTo(parent.bottom) width = Dimension.value(40.dp) height = Dimension.value(40.dp) }, ) } A simple list – Jetpack Compose List item composable - ListItem.kt

Slide 38

Slide 38 text

Webuni webinar – @stewemetal @Composable fun ListItem( item: Item, ) { ConstraintLayout( modifier = Modifier .background(MaterialTheme.colors.background) .height(60.dp) .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), ) { val (text, chevron) = createRefs() Text( text = item.text, color = Grey, fontSize = 16.sp, modifier = Modifier .constrainAs(text) { top.linkTo(parent.top) start.linkTo(parent.start) end.linkTo(chevron.start) bottom.linkTo(parent.bottom) width = Dimension.fillToConstraints }, ) Icon( painterResource(id = R.drawable.ic_chevron_right), tint = Grey, contentDescription = "Item arrow forward", modifier = Modifier .constrainAs(chevron) { top.linkTo(parent.top) start.linkTo(text.end, margin = 16.dp) end.linkTo(parent.end) bottom.linkTo(parent.bottom) width = Dimension.value(40.dp) height = Dimension.value(40.dp) }, ) } A simple list – Jetpack Compose List item composable - ListItem.kt val (text, chevron) = createRefs() Text( text = item.text, color = Grey, fontSize = 16.sp, modifier = Modifier .constrainAs(text) { top.linkTo(parent.top) start.linkTo(parent.start) end.linkTo(chevron.start) bottom.linkTo(parent.bottom) width = Dimension.fillToConstraints }, )

Slide 39

Slide 39 text

Webuni webinar – @stewemetal @Composable fun ComposeContent() { ComposeDemoTheme { Scaffold( topBar = { TopAppBar( title = { Text("Compose implementation") }, ) }, content = { LazyColumn { items((1..30).toList()) { ListItem(Item("Compose item $it")) } } }, ) } } A simple list – Jetpack Compose Content composable - ComposeContent.kt

Slide 40

Slide 40 text

Webuni webinar – @stewemetal @Composable fun ComposeContent() { ComposeDemoTheme { Scaffold( topBar = { TopAppBar( title = { Text("Compose implementation") }, ) }, content = { LazyColumn { items((1..30).toList()) { ListItem(Item("Compose item $it")) } } }, ) } } A simple list – Jetpack Compose Content composable - ComposeContent.kt LazyColumn { items((1..30).toList()) { ListItem(Item("Compose item $it")) } } The equivalent of a RecyclerView + Adapter

Slide 41

Slide 41 text

Webuni webinar – @stewemetal @Composable fun ComposeContent() { ComposeDemoTheme { Scaffold( topBar = { TopAppBar( title = { Text("Compose implementation") }, ) }, content = { LazyColumn { items((1..30).toList()) { ListItem(Item("Compose item $it")) } } }, ) } } A simple list – Jetpack Compose Content composable - ComposeContent.kt

Slide 42

Slide 42 text

Webuni webinar – @stewemetal Fragment - ComposeFragment.kt class ComposeFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View = inflater.inflate(R.layout.fragment_compose, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) view.findViewById(R.id.composeView) .apply { setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed) setContent { ComposeContent() } } } } A simple list – Jetpack Compose

Slide 43

Slide 43 text

Webuni webinar – @stewemetal Fragment - ComposeFragment.kt A simple list – Jetpack Compose class ComposeFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View = inflater.inflate(R.layout.fragment_compose, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) view.findViewById(R.id.composeView) .apply { setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed) setContent { ComposeContent() } } } } view.findViewById(R.id.composeView) .apply { setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed) setContent { ComposeContent() } } Interoperability with Views

Slide 44

Slide 44 text

Webuni webinar – @stewemetal A simple list – View vs. Compose • View • Imperative • 2 layout XMLs • Binding code in a Fragment • RecyclerView adapter • Compose • Declarative • 2 composable functions in Kotlin • 1 layout in XML (interop) • Interop code in a Fragment

Slide 45

Slide 45 text

Webuni webinar – @stewemetal • Start here, please 🙏 Thinking in Compose https://developer.android.com/jetpack/compose/mental-model

Slide 46

Slide 46 text

Webuni webinar – @stewemetal • UI components in Kotlin – as Composable functions • Themes in Kotlin – as Composable functions • and objects in the composition • Value resources in Kotlin • Drawables, strings, dimensions etc. can still come from the usual XML sources thanks to interop features • The UI is composed based on the current state and recomposed when a new state is provided Thinking in Compose UI

Slide 47

Slide 47 text

Webuni webinar – @stewemetal • Initial composition • Calling Composables for the first time • Keeping track of the Composition Composition, recomposition https://developer.android.com/jetpack/compose/lifecycle

Slide 48

Slide 48 text

Webuni webinar – @stewemetal • Initial composition • Calling Composables for the first time • Keeping track of the Composition • Recomposition • When the app state changes, Compose re-executes composables and updates the Composition Composition, recomposition https://developer.android.com/jetpack/compose/lifecycle

Slide 49

Slide 49 text

Webuni webinar – @stewemetal • Initial composition • Calling Composables for the first time • Keeping track of the Composition • Recomposition • When the app state changes, Compose re-executes composables and updates the Composition Composition, recomposition https://developer.android.com/jetpack/compose/lifecycle

Slide 50

Slide 50 text

Webuni webinar – @stewemetal • Use Composable functions to describe UI component hierarchies based on state data that can change over time UI state in Compose UI @Composable fun CustomButton( text: String, loading: Boolean, enabled: Boolean, onClick: () -> Unit, ) { . . . }

Slide 51

Slide 51 text

Webuni webinar – @stewemetal • Use Composable functions to describe UI component hierarchies based on state data that can change over time CustomButton( // . . . loading = false, enabled = false, ) UI state in Compose UI Custom Button

Slide 52

Slide 52 text

Webuni webinar – @stewemetal • Use Composable functions to describe UI component hierarchies based on state data that can change over time CustomButton( // . . . loading = false, enabled = true, ) UI state in Compose UI Custom Button

Slide 53

Slide 53 text

Webuni webinar – @stewemetal • Use Composable functions to describe UI component hierarchies based on state data that can change over time CustomButton( // . . . loading = true, enabled = true, ) UI state in Compose UI

Slide 54

Slide 54 text

Webuni webinar – @stewemetal A life-like project

Slide 55

Slide 55 text

Webuni webinar – @stewemetal A life-like project (🐴)

Slide 56

Slide 56 text

Webuni webinar – @stewemetal How does Compose fit into our lives (and code)? Let’s find out! https://github.com/stewemetal/composehydrationtracker A life-like project (🐴)

Slide 57

Slide 57 text

Webuni webinar – @stewemetal Existing project? No problem! • Composables in existing views • Activities • Fragments • Views in a Composition • Two-way interoperability • Compose works well with existing View-based UI • We can reuse our existing (custom) UI elements

Slide 58

Slide 58 text

Webuni webinar – @stewemetal Existing project? No problem! • Composables in existing views • Activities • Fragments • Views in a Composition • Two-way interoperability • Compose works well with existing View-based UI • We can reuse our existing (custom) UI elements • Migrate at your own pace and educate your team!

Slide 59

Slide 59 text

Webuni webinar – @stewemetal 📚Resources for learning📚

Slide 60

Slide 60 text

Webuni webinar – @stewemetal Resources • The official docs • https://developer.android.com/jetpack/compose/documentation • https://developer.android.com/jetpack/compose/mental-model • https://developer.android.com/jetpack/compose/state • https://developer.android.com/jetpack/compose/lifecycle • Android Developers videos • https://www.youtube.com/c/AndroidDevelopers/search?query=co mpose

Slide 61

Slide 61 text

Webuni webinar – @stewemetal Resources • The Compose Runtime, Demystified • Leland Richardson, KotlinConf ‘19 • https://youtu.be/6BRlI5zfCCk

Slide 62

Slide 62 text

Webuni webinar – @stewemetal Resources • Jetpack Compose internals – Jorge Castillo • https://jorgecastillo.dev/book/ • Pretty theory-heavy!

Slide 63

Slide 63 text

Webuni webinar – @stewemetal Resources • Jetpack Compose basics codelab • https://developer.android.com/codelabs/jetpack- compose-basics

Slide 64

Slide 64 text

Webuni webinar – @stewemetal Resources • Jetpack Compose Samples • https://github.com/android/compose-samples

Slide 65

Slide 65 text

Webuni webinar – @stewemetal Resources • Android Developers Backstage (ADB) podcast • https://adbackstage.libsyn.com/ • Starting with EP 164 • https://adbackstage.libsyn.com/episode-164-jetpack- compose-compilation

Slide 66

Slide 66 text

Webuni webinar – @stewemetal There’s so much more to learn about! • Compose lifecycle and how composition works • State handling • Side effects • Navigation • Animations • Accessibility • Custom theming • Integration testing • . . .

Slide 67

Slide 67 text

Webuni webinar – @stewemetal stewemetal • Less code with the declarative approach • Faster iteration, faster implementation • Easier UI testing • Existing code/resources supported Photo by Xavi Cabrera The Future of Android Development István Juhos Jetpack Compose