Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Jetpack Compose: Beyond I/O 2021

Jetpack Compose: Beyond I/O 2021

Google I/O Extended Korea Android 발표 자료입니다.

Sa-ryong Kang

July 02, 2021
Tweet

More Decks by Sa-ryong Kang

Other Decks in Technology

Transcript

  1. 1 Jetpack Compose: I/O 2021 그 이후 Speaker Saryong Kang

    Partner Developer Advocate @ Google Japan https://speakerdeck.com/saryong
  2. Disclaimer • 이 발표에서 나오는 설명, 해설 및 참고 자료는

    Google의 공식적 내용이 아닐 수 있습니다. • 기술에 대한 의견, 평가는 어디까지나 개인적인 의견입니다. 2
  3. 3 02 Compose로 더 행복해지는 앱 개발 01 I/O 2021

    Quick Recap 03 Compose 개발이 처음이라면 04 실전 Compose! 05 FAQ
  4. • 왜 Compose를 만들었는가? • 왜 선언형 UI인가? • 샘플

    프로젝트 OWL을 통한 UI 구현 데모 5 What’s new in Jetpack Compose
  5. Manuel Vicente Vivo - Developer Relations Engineer, Google @manuelvicnt Using

    Jetpack libraries in Compose 6 Ian Lake - Software Engineer, Google @ianhlake
  6. • 샘플 프로젝트 Bloom 소개 • ViewModel를 중심으로 Compose 앱에서

    어떻게 상태를 관리하는가 설명 • 기존 앱의 마이그레이션 전략 • Compose에서 Navigation 구현 방법 소개 7 Using Jetpack libraries in Compose
  7. • Owl샘플 프로젝트를 이용해 디자인을 어떻게 적용하는가를 설명 • Compose에서

    체계적으로 색상, 폰트, 모양(shape)을 지정하는 방법 • Scaffold등 Material Design Component의 Composable 사용 방법 • Dark mode대응 • MDC-Android Compose Theme Adapter 8 Build beautiful Material Design apps with Jetpack Compose
  8. • Accessibility Test Framework for Android (ATF)의 체크 결과가 Android

    Studio에 표시됨 • Jetpack Compose의 접근성 대응에 대해서 소개 9 Designing for accessibility in Android Studio and Jetpack Compose
  9. 10 02 Compose로 더 행복해지는 앱 개발 01 I/O 2021

    Quick Recap 03 Compose 개발이 처음이라면 04 실전 Compose! 05 FAQ
  10. Button LinearLayout TextView XML Layout findViewById() Activity / Fragment tv.setText()

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

    b.setVisibility() vg.addView() State State State State State
  12. @Composable fun HomeScreen() { var counter by remember { mutableStateOf(0)

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

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

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

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

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

    } Column { Text(text = "현재값: $counter") Button(onClick = { counter++ }) { Text("더하기 1") } } }
  18. • 방대한 코드 베이스로 인해 기술적 부채의 해소가 어려워짐 •

    새로운 디자인 언어(design language)의 구현이 기존 View 구조에서는 어려웠음 • 전체 앱을 Compose 기반으로 바꾸는 작업을 작년부터 진행 중 • 많은 양의 feature request / feedback으로 함께 미래를 만들어 가고 있음 • “다시는 이전의 View 기반으로 돌아가고 싶지 않다” • Ref: d.android.com/stories/apps/mercari 27 사례: Mercari
  19. 28 03 Compose 개발이 처음이라면 04 실전 Compose! 05 FAQ

    01 I/O 2021 Quick Recap 02 Compose로 더 행복해지는 앱 개발
  20. 31 Google 공식 자료들 • 공식 샘플 프로젝트 - 주제별로

    8개의 다양한 샘플 프로젝트 goo.gle/compose-samples • 코드랩 모음 goo.gle/compose-codelabs • 각종 가이드문서 goo.gle/compose-docs (Foundation 파트, 그 중에서도 Thinking in Jetpack Compose!)
  21. 32 Accompanist: 필수 라이브러리 • Compose 안에서 제공하기 애매한 기능들

    ◦ 이미지 로딩: Coil, Glide • 각종 실험적인 기능들 ◦ Insets ◦ Pager ◦ Swipe to Refresh ◦ Permissions • 그 외 각종 실험 예제 - eg. non-AAC state 관리
  22. • 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 자료 (초급)
  23. • 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 자료 (중급)
  24. 35 04 실전 Compose! 05 FAQ 01 I/O 2021 Quick

    Recap 02 Compose로 더 행복해지는 앱 개발 03 Compose 개발이 처음이라면
  25. • State Hoisting • ViewModel • CompositionLocal 하위 노드에서 접근

    가능. Dimension 데이터 등 전역으로 관리하는 상태를 넘겨주기에 적합 36 중요 개념: 상태 전달
  26. • Composable 외부로부터 영향을 받는 부수작용을 처리하기 위한 Composable ◦

    SideEffect / DisposableEffect ◦ Eg. 서버 호출, DB 쿼리 등 37 중요 개념: SideEffect
  27. 38 중요 개념: Custom Layout • Modifier.layout → 같은 프레임을

    빠르게 그려줌 ◦ 부모 트리의 영향을 받는 개발 composable의 size/padding을 변경하는 경우에 추천 ◦ 구조적인 변경(orientation, positioning)엔 적합하지 않음 • Modifier.onSizeChanged ◦ 데이터 로딩 등을 위해 사이즈 정보가 필요한 경우에 추천 ◦ MutableState 전달에 의해 그린다면 한 프레임씩 지연이 생김에 주의 • WithConstraints → 같은 프레임에 그리지만 subcomposition이 일어남 ◦ 구조적인 변경에 추천
  28. • UI의 재구축(recomposition)은 될 수 있는 한 skip되도록 설계되어 있다.

    Ref: d.android.com/jetpack/compose/mental-model#skips • 어디서 재구축이 어떻게 일어나는 지 이해하지 않아도 괜찮음. Compose compiler/runtime이 알아서.. 39 중요 개념: Position Memoization
  29. data class State( val firstCounter: Int = 0, val secondCounter:

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

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

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

    Int = 0 ) @Composable fun HomeScreen( stateFlow: StateFlow<State>, onClick1: () -> Unit, onClick2: () -> Unit, ) { val state by stateFlow.collectAsState() Column { Button(onClick = onClick1) { Text(text = "첫째 카운터: ${state.firstCounter}") } Button(onClick = onClick2) { Text(text = "둘째 카운터 ${state.secondCounter}") } } }
  33. • 딱 두 가지 유의점 ◦ inline composable 함수 ◦

    Composition 비용이 많이 들 것 같은 경우는, 관계없는 상태에 영향을 받지 않도록 분리할 필요가 있음 44 Tip: Recomposition 최적화
  34. • 하나의 Preview Composable에 옵션별로 여러 개의 @Preview 애너테이션 달기

    ◦ 평소에는 작은 사이즈(eg. 360dp X 640dp)만 활성화 • “Deploy Preview” 기능 • 참고: 현재 rc01 에서 프리뷰가 보이지 않는 문제는 차기 Android Studio 릴리즈에서 해결됩니다 45 Tip: Preview
  35. @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() } } }
  36. • 전통적인 Android View에서는 할 수 있는 한 nest 되지

    않는 것이 관건이지만, Compose에서는 문제가 되지 않음 • 반대로, 앞서 얘기한 이유로, nesting을 줄이면 오히려 성능이 급격히 저하되는 경우가 많음 47 Tip: ConstraintLayout
  37. • Color를 resource로부터 얻지 말고 Kotlin 코드로 정의할 것 (JNI

    call 발생) • · 과 같은 유니코드 문자를 빈번히 렌더링할 경우, Text() 대신 Canvas() 사용을 검토할 것 → 훨씬 빠름 48 Tip: 그외 깨알 성능 팁
  38. 49 05 FAQ 01 I/O 2021 Quick Recap 02 Compose로

    더 행복해지는 앱 개발 03 Compose 개발이 처음이라면 04 실전 Compose!