Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Adopting Jetpack Compose in Your Existing Proje...
Search
Somkiat Khitwongwattana
November 17, 2024
Technology
240
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Adopting Jetpack Compose in Your Existing Project - GDG DevFest Bangkok 2024
"Adopting Jetpack Compose in your existing project" at GDG DevFest Bangkok 2024
Somkiat Khitwongwattana
November 17, 2024
More Decks by Somkiat Khitwongwattana
See All by Somkiat Khitwongwattana
Snackbar in Compose with Friendly UI Testing
akexorcist
0
260
Gemini in Android Studio - Google I/O Bangkok '25
akexorcist
0
520
Why App Signing Matters for Your Android Apps - Android Bangkok Conference 2024
akexorcist
1
790
Building the automated Android UI testing in Continuous integration at LINE MAN Wongnai
akexorcist
1
950
Building the automated Android UI testing in Continuous integration at LINE MAN Wongnai
akexorcist
1
91
What's new in Android 14 - IO Extended George Town 2023
akexorcist
1
390
All you need to know about new Logcat in Android Studio - DevFest Bangkok 2022
akexorcist
0
120
Backend for mobile app - Droidcon SG 2022
akexorcist
0
130
Backend for mobile app - Android Bangkok Conference 2022
akexorcist
1
210
Other Decks in Technology
See All in Technology
金融の未来を考える / Thinking About the Future of Finance
ks91
PRO
0
150
知見・人・API・DB・予算 ─ ナイナイ尽くしだった人事データ整備 with dbt、5年間の学び
ken6377
1
150
Amazon EVS で VCF 9.0 / 9.1 のサポート開始まとめ
mtoyoda
0
200
プロンプト_きのこカンファレンス2026_LT
yurufuwahealer
0
130
記録をかんたんに、提案をパーソナルに ── AIであすけんが目指すもの
oprstchn
0
140
AI Agentをシステムに組み込む前にゆるく向き合ってみる
hayama17
0
200
NDIAS CTF 2026 問題解説会資料
bata_24
0
170
#エンジニアBooks 30分でわかる 「技術記事を書く技術」 / engineer-books 2026-06-30
jnchito
1
190
フルAIで個人開発して学んだあれこれ / yuruai vol.1
isaoshimizu
0
170
デジタル・デザイン:次の50年を描く「進化する青写真」
y150saya
0
800
Kotlin 開発のツラミを爆破した話! / Explode the difficulty of Kotlin dev!
eller86
0
140
CVE-2026-20833_脆弱性対応とAES 化について
jukishiya
0
360
Featured
See All Featured
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4.1k
Test your architecture with Archunit
thirion
1
2.3k
Unsuck your backbone
ammeep
672
58k
Evolving SEO for Evolving Search Engines
ryanjones
0
230
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
180
Building Flexible Design Systems
yeseniaperezcruz
330
40k
It's Worth the Effort
3n
188
29k
The browser strikes back
jonoalderson
0
1.4k
Become a Pro
speakerdeck
PRO
31
6k
Bash Introduction
62gerente
615
220k
Color Theory Basics | Prateek | Gurzu
gurzu
0
380
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Transcript
Adopting Jetpack Compose in Your Existing Project Bangkok Somkiat Khitwongwattana
Android GDE
Less code Intuitive Accelerate development Powerful Why Jetpack Compose?
Less code Intuitive Accelerate development Powerful Why Jetpack Compose?
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <Button
android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" /> </LinearLayout> Build an UI with XML
class MainActivity : AppCompatActivity() { private val binding: ActivityMainBinding by
lazy { ... } override fun onCreate(savedInstanceState: Bundle?) { ... binding.button.setOnClickListener { // Do something } } } View binding
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
... setContent { ComposeAppTheme { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center, ) { Button(onClick = { // Do something }) { Text(text = "Button") Build an UI with Jetpack Compose
setContent { ComposeAppTheme { Box( ... ) { Button(onClick =
{ // Do something }) { Text(text = "Button") } } } } Build an UI with Jetpack Compose
Less code Intuitive Accelerate development Powerful Why Jetpack Compose?
<Button android:id="@+id/button3" android:text="Button 3" android:visibility="gone" /> <LinearLayout> <Button android:id="@+id/button1" android:text="Button
1" /> <Button android:id="@+id/button2" android:text="Button 2" /> </LinearLayout> Readability
<Button android:id="@+id/button3" android:text="Button 3" android:visibility="gone" /> <LinearLayout> <Button android:id="@+id/button1" android:text="Button
1" /> <Button android:id="@+id/button2" android:text="Button 2" /> </LinearLayout> Readability
val button1: Button = /* ... */ val button2: Button
= /* ... */ val button3: Button = /* ... */ val isPurchased = false button1.visibility = if (isPurchased) View.GONE else View.VISIBLE button2.visibility = if (isPurchased) View.GONE else View.VISIBLE button3.visibility = if (isPurchased) View.VISIBLE else View.GONE Readability
val button1: Button = /* ... */ val button2: Button
= /* ... */ val button3: Button = /* ... */ val isPurchased = true button1.visibility = if (isPurchased) View.GONE else View.VISIBLE button2.visibility = if (isPurchased) View.GONE else View.VISIBLE button3.visibility = if (isPurchased) View.VISIBLE else View.GONE Readability
val isPurchased: Boolean = ... Box( ... ) { if
(isPurchased) { Button( ... ) { Text("Button 3") } } else { Row( ... ) { Button( ... ) { Text("Button 1") } Spacer( ... ) Button( ... ) { Text("Button 2") } } } } Readability
Less code Intuitive Accelerate development Powerful Why Jetpack Compose?
data class Item( val id: String, val text: String, )
Dynamic list UI
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textViewItem" android:layout_width="match_parent"
android:layout_height="wrap_content" /> </FrameLayout> Dynamic list UI
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent"
android:layout_height="match_parent" /> </FrameLayout> Dynamic list UI
class ItemViewHolder( private val binding: LayoutListItemBinding ) : ViewHolder(binding.root) {
fun bind(item: Item) { binding.textViewItem.text = item.text } } Dynamic list UI
class ListAdapter(private val items: List<Item>) : RecyclerView.Adapter<ItemViewHolder>() { override fun
onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( LayoutListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) ) override fun getItemCount(): Int = items.size override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { items.getOrNull(position)?.let { holder.bind(it.text) } } } Dynamic list UI
val items: List<Item> = /* ... */ val context: Context
= /* ... */ with(binding.recyclerView) { layoutManager = LinearLayoutManager( context, LinearLayoutManager.VERTICAL, false, ) adapter = ListAdapter(items) } Dynamic list UI
@Composable fun ListContent(items: List<Item>) { LazyColumn(modifier = Modifier.fillMaxSize()) { items(
items = items, key = { item -> item.id } ) { item -> Text( modifier = Modifier.fillMaxWidth(), text = item.text, ) } } Dynamic list UI
Less code Intuitive Accelerate development Powerful Why Jetpack Compose?
var activated by remember { mutableStateOf(true) } val contentColor by
animateColorAsState( ... ) val containerColor by animateColorAsState( ... ) val scale by animateFloatAsState( ... ) Button( modifier = Modifier.scale(scale), colors = ButtonDefaults.buttonColors( containerColor = containerColor, contentColor = contentColor, ), onClick = { activated = !activated }, ) { Text(if (activated) "Activated" else "Inactivated") } Animation
Jetpack Compose 1.7.5 is now available
Declarative programming paradigm Declarative paradigm shift Dynamic content Recomposition Thinking
in Compose
Declarative paradigm shift • Relatively stateless and don't expose setter
or getter functions • Update the UI by passing the different arguments • Unidirectional data flow
State flows down
Event flows up
@Composable fun ProfileContent(name: String, status: String, onEditProfile: () -> Unit)
{ Row { Box{ Image( ... ) IconButton(onClick = onEditProfile) { ... } } Column { Text(name) Text(status) } } } State flows down and event flows up
@Composable fun ProfileContent(name: String, status: String, onEditProfile: () -> Unit)
{ Row { Box{ Image( ... ) IconButton(onClick = onEditProfile) { ... } } Column { Text(name) Text(status) } } } State flows down and event flows up
@Composable fun ProfileContent(name: String, status: String, onEditProfile: () -> Unit)
{ Row { Box{ Image( ... ) IconButton(onClick = onEditProfile) { ... } } Column { Text(name) Text(status) } } } State flows down and event flows up
@Composable fun ProfileContent(name: String, status: String, onEditProfile: () -> Unit)
{ Row { Box{ Image( ... ) IconButton(onClick = onEditProfile) { ... } } Column { Text(name) Text(status) } } } State flows down and event flows up
@Composable fun TopThreeItems(items: List<String>) { Column { HeaderContent() items.take(3).forEach {
item -> ItemContent(item) } } } Dynamic content
@Composable fun TopThreeItems(items: List<String>) { Column { HeaderContent() items.take(3).forEach {
item -> ItemContent(item) } } } Recomposition New value update
@Composable fun TopThreeItems(items: List<String>) { Column { HeaderContent() items.take(3).forEach {
item -> ItemContent(item) } } } Recomposition Skip
@Composable fun TopThreeItems(items: List<String>) { Column { HeaderContent() items.take(3).forEach {
item -> ItemContent(item) } } } Recomposition Recomposition
Get started Jetpack Compose for Android Developers https://developer.android.com/courses/jetpack-compose/course
Get started
Get started https://github.com/android/nowinandroid
Get started https://github.com/chrisbanes/tivi
Why should you adopt Jetpack Compose?
Chance for the big improvement Animate with a few lines
of code Powerful preview in Android Studio Testable without view ID Friendly for sub-component creation Benefit for teams
Powerful preview in Android Studio
@Composable fun MainScreen( ... ) { Column( ... ) {
Profile( modifier = Modifier.testTag("profile"), ... ) ... } } Testable without view ID
<node index="0" text="" resource-id="" class="android.view.View" package="com.akexorcist.devfest" content-desc="" checkable="false" checked="false" clickable="false"
enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,66][79,132]"> <node index="0" text="Android" resource-id="" class="android.widget.TextView" package="com.akexorcist.devfest" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,66][79,132]" /> </node> Testable without view ID
<node index="0" text="" resource-id="" class="android.view.View" package="com.akexorcist.devfest" content-desc="" checkable="false" checked="false" clickable="false"
enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,66][79,132]"> <node index="0" text="Android" resource-id="" class="android.widget.TextView" package="com.akexorcist.devfest" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,66][79,132]" /> </node> Testable without view ID
<node index="0" text="" resource-id="" class="android.view.View" package="com.akexorcist.devfest" content-desc="" checkable="false" checked="false" clickable="false"
enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,66][79,132]"> <node index="0" text="Android" resource-id="" class="android.widget.TextView" package="com.akexorcist.devfest" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,66][79,132]" /> </node> Testable without view ID
Friendly for sub-component creation
Fragment Friendly for sub-component creation Fragment Fragment Fragment ViewModel ViewModel
ViewModel ViewModel ViewModel
View Friendly for sub-component creation View View View ViewModel
Compose Friendly for sub-component creation Compose Compose Compose ViewModel ViewModel
ViewModel ViewModel ViewModel
@Composable fun FirstSection(viewModel: FirstViewModel = koinViewModel()) { ... } @Composable
fun SecondSection(viewModel: SecondViewModel = koinViewModel()) { ... } @Composable fun ThirdSection(viewModel: ThirdViewModel = koinViewModel()) { ... } @Composable fun FourthSection(viewModel: FourthViewModel = koinViewModel()) { ... } Friendly for sub-component creation
@Composable fun MainScreen(viewModel: MainViewModel = koinViewModel()) { Column { FirstSection()
SecondSection() ThirdSection() FourthSection() } } Friendly for sub-component creation
@Composable fun MainScreen(viewModel: MainViewModel = koinViewModel()) { LazyColumn { item(key
= "first") { FirstSection() } item(key = "second") { SecondSection() } item(key = "third") { ThirdSection() } item(key = "fourth") { FourthSection() } } } Friendly for sub-component creation
Activity Result Requesting Runtime Permissions ViewModel Data Streams Asynchronous Operations
Availability
Screen Navigation Dependency Injection Google Maps Navigation Drawer Bottom Sheet
Availability
Nested Scrolling Material 3 Components Dialog Snackbar Image Loading Availability
WindowInsets Handling screen size changed Availability UI Testing
Compose preview generation with Gemini
Things to know Debug build performance Profile installer for better
performance No cost from XML layout inflation Efficiently handle deep UI trees Smart recompositions
Sunflower app https://github.com/android/sunflower
APK Size Based on information from the Sunflower app Views
only 2,252 KB 3,034 KB 2,966 KB Mixed Views and Compose Compose-only
Build Time Based on information from the Sunflower app Views
only 299.47 ms 399.09 ms 342.16 ms Mixed Views and Compose Compose-only
Tivi app https://github.com/chrisbanes/tivi
Based on information from the Tivi app v1.0.0-rc01 APK Size
Views only 4.14 MB 2.71 MB 2.32 MB Fragment and Compose Compose-only
Method Count Based on information from the Tivi app v1.0.0-rc01
Views only 40,029 35,165 23,689 Fragment and Compose Compose-only
In the other side Different knowledge Few performance overhead based
on complexity Fewer third-party libraries compared to the View Limited legacy support
None
Approach to integrating Jetpack Compose New Features Simple Component or
Screen Redesign Features
Fragment Layout Layout View Layout View View Compose
Activity Activity Activity Activity Activity View View View Compose
Activity Fragment Fragment Fragment Fragment View View View Compose
Activity Activity Activity Fragment Navigation View Compose Fragment View Compose
Compose
Activity Activity Activity Fragment Navigation View Compose Fragment View Compose
Compose
Activity Fragment Fragment Fragment Navigation View Compose Fragment View Compose
Compose
Activity Fragment Fragment Fragment Navigation View Compose Fragment View Compose
Compose
Activity Fragment Fragment Fragment Navigation View Compose Fragment View Compose
Compose
Codebase Navigation Existing UI Component & Design System Analytics Testing
Things to think about
Compose in Activity Fragment View Compose View in
class MainActivity: ComponentActivity() { override fun onCreate( ... ) {
... setContent { // In Compose world } } } Compose in Activity
class HomeFragment : Fragment() { override fun onCreateView( ... ):
View { return ComposeView(requireContext()).apply { setViewCompositionStrategy( ... ) setContent { // In Compose world } } } } Compose in Fragment
Compose in View <?xml version="1.0" encoding="utf-8"?> <FrameLayout> ... <androidx.compose.ui.platform.ComposeView android:id="@+id/composeView"
android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
val composeView = findViewById<ComposeView>(R.id.composeView) composeView.apply { setViewCompositionStrategy( ... ) setContent
{ // In Compose world } } Compose in View
@Composable fun AndroidCustomView(title: String, onClick: () -> Unit) { AndroidView(
factory = { context -> CustomView(context).apply { setOnClickListener(onClick) } }, update = { view -> view.setTitle(title) } ) View in Compose
Codebase preparation for seamless feature development Start with small, incremental
changes Learning resources for future adopters Negotiate with the product's decision-maker To make it happen
API Maturity Learning resources Libraries & tools Backward compatibility Multiplatform
supported Jetpack Compose is now production-ready Performance Wide Adoption
"Any code you built with views will become technical debt"
Florina Muntenescu
Thank you Bangkok