Slide 1

Slide 1 text

1 Jetpack Compose: I/O 2021 그 이후 Speaker Saryong Kang Partner Developer Advocate @ Google Japan https://speakerdeck.com/saryong

Slide 2

Slide 2 text

Disclaimer ● 이 발표에서 나오는 설명, 해설 및 참고 자료는 Google의 공식적 내용이 아닐 수 있습니다. ● 기술에 대한 의견, 평가는 어디까지나 개인적인 의견입니다. 2

Slide 3

Slide 3 text

3 02 Compose로 더 행복해지는 앱 개발 01 I/O 2021 Quick Recap 03 Compose 개발이 처음이라면 04 실전 Compose! 05 FAQ

Slide 4

Slide 4 text

Anna-Chiara Bellini @dr0nequeen Clara Bayarri @clarabayarri What’s new in Jetpack Compose

Slide 5

Slide 5 text

● 왜 Compose를 만들었는가? ● 왜 선언형 UI인가? ● 샘플 프로젝트 OWL을 통한 UI 구현 데모 5 What’s new in Jetpack Compose

Slide 6

Slide 6 text

Manuel Vicente Vivo - Developer Relations Engineer, Google @manuelvicnt Using Jetpack libraries in Compose 6 Ian Lake - Software Engineer, Google @ianhlake

Slide 7

Slide 7 text

● 샘플 프로젝트 Bloom 소개 ● ViewModel를 중심으로 Compose 앱에서 어떻게 상태를 관리하는가 설명 ● 기존 앱의 마이그레이션 전략 ● Compose에서 Navigation 구현 방법 소개 7 Using Jetpack libraries in Compose

Slide 8

Slide 8 text

● Owl샘플 프로젝트를 이용해 디자인을 어떻게 적용하는가를 설명 ● Compose에서 체계적으로 색상, 폰트, 모양(shape)을 지정하는 방법 ● Scaffold등 Material Design Component의 Composable 사용 방법 ● Dark mode대응 ● MDC-Android Compose Theme Adapter 8 Build beautiful Material Design apps with Jetpack Compose

Slide 9

Slide 9 text

● Accessibility Test Framework for Android (ATF)의 체크 결과가 Android Studio에 표시됨 ● Jetpack Compose의 접근성 대응에 대해서 소개 9 Designing for accessibility in Android Studio and Jetpack Compose

Slide 10

Slide 10 text

10 02 Compose로 더 행복해지는 앱 개발 01 I/O 2021 Quick Recap 03 Compose 개발이 처음이라면 04 실전 Compose! 05 FAQ

Slide 11

Slide 11 text

XML Layout Button LinearLayout TextView

Slide 12

Slide 12 text

Button LinearLayout TextView XML Layout findViewById() Activity / Fragment tv.setText() b.setVisibility() vg.addView()

Slide 13

Slide 13 text

Button LinearLayout TextView XML Layout findViewById() Activity / Fragment tv.setText() b.setVisibility() vg.addView() State

Slide 14

Slide 14 text

Button LinearLayout TextView XML Layout findViewById() Activity / Fragment tv.setText() b.setVisibility() vg.addView() State State

Slide 15

Slide 15 text

Button LinearLayout TextView XML Layout findViewById() Activity / Fragment tv.setText() b.setVisibility() vg.addView() State State State State State

Slide 16

Slide 16 text

Button LinearLayout TextView XML Layout findViewById() Activity / Fragment tv.setText() b.setVisibility() vg.addView() State State State State State

Slide 17

Slide 17 text

UI State

Slide 18

Slide 18 text

UI State 2

Slide 19

Slide 19 text

UI 2 State 2

Slide 20

Slide 20 text

UI 2 State 2

Slide 21

Slide 21 text

@Composable fun HomeScreen() { var counter by remember { mutableStateOf(0) } Column { Text(text = "현재값: $counter") Button(onClick = { counter++ }) { Text("더하기 1") } } }

Slide 22

Slide 22 text

@Composable fun HomeScreen() { var counter by remember { mutableStateOf(0) } Column { Text(text = "현재값: $counter") Button(onClick = { counter++ }) { Text("더하기 1") } } }

Slide 23

Slide 23 text

@Composable fun HomeScreen() { var counter by remember { mutableStateOf(0) } Column { Text(text = "현재값: $counter") Button(onClick = { counter++ }) { Text("더하기 1") } } }

Slide 24

Slide 24 text

@Composable fun HomeScreen() { var counter by remember { mutableStateOf(0) } Column { Text(text = "현재값: $counter") Button(onClick = { counter++ }) { Text("더하기 1") } } }

Slide 25

Slide 25 text

@Composable fun HomeScreen() { var counter by remember { mutableStateOf(0) } Column { Text(text = "현재값: $counter") Button(onClick = { counter++ }) { Text("더하기 1") } } }

Slide 26

Slide 26 text

@Composable fun HomeScreen() { var counter by remember { mutableStateOf(0) } Column { Text(text = "현재값: $counter") Button(onClick = { counter++ }) { Text("더하기 1") } } }

Slide 27

Slide 27 text

● 방대한 코드 베이스로 인해 기술적 부채의 해소가 어려워짐 ● 새로운 디자인 언어(design language)의 구현이 기존 View 구조에서는 어려웠음 ● 전체 앱을 Compose 기반으로 바꾸는 작업을 작년부터 진행 중 ● 많은 양의 feature request / feedback으로 함께 미래를 만들어 가고 있음 ● “다시는 이전의 View 기반으로 돌아가고 싶지 않다” ● Ref: d.android.com/stories/apps/mercari 27 사례: Mercari

Slide 28

Slide 28 text

28 03 Compose 개발이 처음이라면 04 실전 Compose! 05 FAQ 01 I/O 2021 Quick Recap 02 Compose로 더 행복해지는 앱 개발

Slide 29

Slide 29 text

● 먼저 Pathways! d.android.com/courses/pathways/compose 29 어떻게 공부하면 되나?

Slide 30

Slide 30 text

30 ● 3개의 비디오 강의 ● 2개의 글 ● 7개의 코드랩 ● 1개의 퀴즈

Slide 31

Slide 31 text

31 Google 공식 자료들 ● 공식 샘플 프로젝트 - 주제별로 8개의 다양한 샘플 프로젝트 goo.gle/compose-samples ● 코드랩 모음 goo.gle/compose-codelabs ● 각종 가이드문서 goo.gle/compose-docs (Foundation 파트, 그 중에서도 Thinking in Jetpack Compose!)

Slide 32

Slide 32 text

32 Accompanist: 필수 라이브러리 ● Compose 안에서 제공하기 애매한 기능들 ○ 이미지 로딩: Coil, Glide ● 각종 실험적인 기능들 ○ Insets ○ Pager ○ Swipe to Refresh ○ Permissions ● 그 외 각종 실험 예제 - eg. non-AAC state 관리

Slide 33

Slide 33 text

● View <-> Compose mapping table https://jetpackcompose.app/What-is-the-equivalent-of-CardView-in-Jetpack-Compose 예: FrameLayout → Stack, SeekBar → Slider, EditText → TextField ● Learn Jetpack Compose By Example https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example ● Joe Birch Blog - Exploring Jetpack Compose https://joebirch.co/ ● 그리고, 여러분.. 33 그외 비 Google 자료 (초급)

Slide 34

Slide 34 text

● Compose From First Principles by Leland Richardson http://intelligiblebabble.com/compose-from-first-principles/ ● Compose State Explained Series by Zach Klippenstein https://dev.to/zachklipp/series/12895 ● Tivi by Chris Banes https://github.com/chrisbanes/tivi ● 그리고.. 34 그외 비 Google 자료 (중급)

Slide 35

Slide 35 text

35 04 실전 Compose! 05 FAQ 01 I/O 2021 Quick Recap 02 Compose로 더 행복해지는 앱 개발 03 Compose 개발이 처음이라면

Slide 36

Slide 36 text

● State Hoisting ● ViewModel ● CompositionLocal 하위 노드에서 접근 가능. Dimension 데이터 등 전역으로 관리하는 상태를 넘겨주기에 적합 36 중요 개념: 상태 전달

Slide 37

Slide 37 text

● Composable 외부로부터 영향을 받는 부수작용을 처리하기 위한 Composable ○ SideEffect / DisposableEffect ○ Eg. 서버 호출, DB 쿼리 등 37 중요 개념: SideEffect

Slide 38

Slide 38 text

38 중요 개념: Custom Layout ● Modifier.layout → 같은 프레임을 빠르게 그려줌 ○ 부모 트리의 영향을 받는 개발 composable의 size/padding을 변경하는 경우에 추천 ○ 구조적인 변경(orientation, positioning)엔 적합하지 않음 ● Modifier.onSizeChanged ○ 데이터 로딩 등을 위해 사이즈 정보가 필요한 경우에 추천 ○ MutableState 전달에 의해 그린다면 한 프레임씩 지연이 생김에 주의 ● WithConstraints → 같은 프레임에 그리지만 subcomposition이 일어남 ○ 구조적인 변경에 추천

Slide 39

Slide 39 text

● UI의 재구축(recomposition)은 될 수 있는 한 skip되도록 설계되어 있다. Ref: d.android.com/jetpack/compose/mental-model#skips ● 어디서 재구축이 어떻게 일어나는 지 이해하지 않아도 괜찮음. Compose compiler/runtime이 알아서.. 39 중요 개념: Position Memoization

Slide 40

Slide 40 text

data class State( val firstCounter: Int = 0, val secondCounter: Int = 0 ) @Composable fun HomeScreen( stateFlow: StateFlow, onClick1: () -> Unit, onClick2: () -> Unit, ) { val state by stateFlow.collectAsState() Column { Button(onClick = onClick1) { Text(text = "첫째 카운터: ${state.firstCounter}") } Button(onClick = onClick2) { Text(text = "둘째 카운터 ${state.secondCounter}") } } }

Slide 41

Slide 41 text

data class State( val firstCounter: Int = 0, val secondCounter: Int = 0 ) @Composable fun HomeScreen( stateFlow: StateFlow, onClick1: () -> Unit, onClick2: () -> Unit, ) { val state by stateFlow.collectAsState() Column { Button(onClick = onClick1) { Text(text = "첫째 카운터: ${state.firstCounter}") } Button(onClick = onClick2) { Text(text = "둘째 카운터 ${state.secondCounter}") } } }

Slide 42

Slide 42 text

data class State( val firstCounter: Int = 0, val secondCounter: Int = 0 ) @Composable fun HomeScreen( stateFlow: StateFlow, onClick1: () -> Unit, onClick2: () -> Unit, ) { val state by stateFlow.collectAsState() Column { Button(onClick = onClick1) { Text(text = "첫째 카운터: ${state.firstCounter}") } Button(onClick = onClick2) { Text(text = "둘째 카운터 ${state.secondCounter}") } } }

Slide 43

Slide 43 text

data class State( val firstCounter: Int = 0, val secondCounter: Int = 0 ) @Composable fun HomeScreen( stateFlow: StateFlow, onClick1: () -> Unit, onClick2: () -> Unit, ) { val state by stateFlow.collectAsState() Column { Button(onClick = onClick1) { Text(text = "첫째 카운터: ${state.firstCounter}") } Button(onClick = onClick2) { Text(text = "둘째 카운터 ${state.secondCounter}") } } }

Slide 44

Slide 44 text

● 딱 두 가지 유의점 ○ inline composable 함수 ○ Composition 비용이 많이 들 것 같은 경우는, 관계없는 상태에 영향을 받지 않도록 분리할 필요가 있음 44 Tip: Recomposition 최적화

Slide 45

Slide 45 text

● 하나의 Preview Composable에 옵션별로 여러 개의 @Preview 애너테이션 달기 ○ 평소에는 작은 사이즈(eg. 360dp X 640dp)만 활성화 ● “Deploy Preview” 기능 ● 참고: 현재 rc01 에서 프리뷰가 보이지 않는 문제는 차기 Android Studio 릴리즈에서 해결됩니다 45 Tip: Preview

Slide 46

Slide 46 text

@Preview(name = "Day mode, small screen", widthDp = 360, heightDp = 640) @Preview( name = "Night mode, small screen", widthDp = 360, heightDp = 640, uiMode = Configuration.UI_MODE_NIGHT_YES, ) @Preview("Day mode, big font", fontScale = 1.5f) @Preview(name = "Day mode", device = Devices.PIXEL_4) @Composable fun PreviewHome() { MyApplicationTheme { Surface(color = MaterialTheme.colors.background) { HomeScreen() } } }

Slide 47

Slide 47 text

● 전통적인 Android View에서는 할 수 있는 한 nest 되지 않는 것이 관건이지만, Compose에서는 문제가 되지 않음 ● 반대로, 앞서 얘기한 이유로, nesting을 줄이면 오히려 성능이 급격히 저하되는 경우가 많음 47 Tip: ConstraintLayout

Slide 48

Slide 48 text

● Color를 resource로부터 얻지 말고 Kotlin 코드로 정의할 것 (JNI call 발생) ● · 과 같은 유니코드 문자를 빈번히 렌더링할 경우, Text() 대신 Canvas() 사용을 검토할 것 → 훨씬 빠름 48 Tip: 그외 깨알 성능 팁

Slide 49

Slide 49 text

49 05 FAQ 01 I/O 2021 Quick Recap 02 Compose로 더 행복해지는 앱 개발 03 Compose 개발이 처음이라면 04 실전 Compose!

Slide 50

Slide 50 text

Compose가 널리 보급되면 기존의 View 구현 방식은 deprecated 되나요? 50

Slide 51

Slide 51 text

XML 자체도 필요없게 될까요? 51

Slide 52

Slide 52 text

기존 Android View와 섞어써도 문제 없을까요? 52

Slide 53

Slide 53 text

Compose를 쓰면 여러 가지 종류의 폼팩터 (form factor) 지원도 쉬워지나요? 53

Slide 54

Slide 54 text

● 이미 가능! https://github.com/chrisbanes/tivi/pull/806/files#diff-2107f2dfb7cd4fe4cf4775d762d2166 afaca1a3625361e58389a0772b179e2a2 ● Stay tunes! 더 강력한 multi form factor 지원이 발표될 예정입니다. ● Wear OS용 컴포즈 alpha01 릴리즈! 🎉 54

Slide 55

Slide 55 text

Thank you! https://speakerdeck.com/saryong Resources 55 Saryong Kang Partner Developer Advocate @ Google Japan