개발 스프린트를 마무리 하고 쉬엄쉬엄 재정비하는 시간을 가지면서 Jetpack Compose 로 마이그레이션해보고자 한다.
이전부터 매우 공부해보고 싶었는데 빠르게 개발 속도를 내야하다보니 어쩔 수 없이 익숙한 걸로 계속 개발하게 되었다...
조금 여유로울 때 많이 공부해놔야겠다.
✅ Jetpack Compose로 변경하는 이유
[선언형 UI]
기존의 xml로 뷰를 구성하는 방식은 명령형 UI에 해당한다.
데이터가 변경되면 UI에 접근하여 데이터가 변경되었으니 UI객체에 새로 업데이트 해라!라고 명령하는 방식이다.
이 과정에서 서로 잘못 연결되거나 누락되면 NPE등의 에러가 발생할 수 있다. 화면이 복잡해질 수록 이런 가능성이 높아진다.
Jetpack Compose는 선언형 UI로 위와 같은 작업을 할 필요가 없다.
개념적으로 UI전체를 재생성한 후 필요한 변경사항만 적용하는 방식이다. UI객체와 연관성을 생각할 필요없이 오직 Kotlin 코드로만 작성하는 것이 가장 큰 매력이 아닐까 싶다.
[빌드시간 단축]
Compose를 이용하여 UI를 구성하면 빌드시간이 단축된다고 한다. 하지만 기존의 View체계와 혼합하여 사용하면 빌드시간이 더 늘어난다고 한다.
모든 코드를 Compose로 전환하기에는 아직 공수비용이 크기 때문에 계획을 잘 세워야할 것 같다.
⚙️ Gradle Setting
해당 gradle은 kotlin dsl이 적용되었기 때문에 기존의 groovy 문법과는 상이하다!
✅ kotlin version: 1.5.30 -> 1.6.10
✅ Java version: 1.8 -> 11
✅ Compose version: 1.1.0
✅ buildFeatures에 compose = true 추가

- 이후 필요한 library들을 dependencies에 추가해주면 된다.
하단에 있는 라이브러리 이외에도 navigtaion compose, coil compose 등 필요에 따라 추가하여 사용하였다.
object Compose {
const val COMPOSE_RUNTIME = "androidx.compose.runtime:runtime:${DependencyVersions.COMPOSE_VERSION}"
const val ACTIVITY_COMPOSE = "androidx.activity:activity-compose:${DependencyVersions.ACTIVITY_KTX_VERSION}"
const val MATERIAL_COMPOSE = "androidx.compose.material:material:${DependencyVersions.COMPOSE_VERSION}"
const val COMPOSE_RUNTIME_LIVEDATA = "androidx.compose.runtime:runtime-livedata:${DependencyVersions.COMPOSE_VERSION}"
const val UI_TOOLING = "androidx.compose.ui:ui-tooling:${DependencyVersions.COMPOSE_VERSION}"
const val COMPOSE_ANIMATION = "androidx.compose.animation:animation:${DependencyVersions.COMPOSE_VERSION}"
const val VIEWMODEL_COMPOSE = "androidx.lifecycle:lifecycle-viewmodel-compose:${DependencyVersions.VIEWMODEL_COMPOSE_VERSION}"
const val COMPOSE_UI_TEST = "androidx.compose.ui:ui-test-junit4:${DependencyVersions.COMPOSE_VERSION}"
}
📃 Migration Plan
- 우선 기초부터 공부를 하면서 진행해야하기 때문에, UI구성이 간단한 부분부터 진행을 하기로 생각했다.
- 이후 xml에 작성된 컴포넌트들을 모두 ComposeView로 바꿔보고,
- 이후에는 xml을 완전히 분리하고 binding을 사용하지 않는 방식으로 진행하고자 한다.
🛠 ComposeView
기존 xml에 선언된 TextView와 변경한 ComposeView이다.
레이아웃은 우선 기존에 사용하던 ConstraintLayout을 그대로 놔뒀다.
나중에는 ConstraintLayout도 xml도 모두 제거할 예정이다!


ComposeView에 Text추가해주면 되는데 정말 간단하다.

📝 리스트 뷰 구현하기
ComopseView로 바꿔보면서 느낀 가장 큰 차이점은 리스트 형식의 뷰를 구성하는 방법이 많이 달라졌다는 것이다.
기존에는 RecyclerView를 이용하여 구현했지만, 이제는 Row와 Column을 이용하여 구현하면 된다.

사진과 같은 뷰를 만들기 위해서는 크게 3가지 과정으로 구분할 수 있을 것이다.
1️⃣ 이번주 날짜들을 계산한다.
2️⃣ 서버에서 각 날짜별 수업횟수를 불러온다.
3️⃣ Row에 각 아이템들을 추가해준다.
1번과 2번은 기존에 구현했던 작업들 이였기에 수정할 필요는 없었고, 리스트를 구현하는 방식과 갱신하는 방식에 차이가 있었다.
[ Item을 만드는 Composable 함수 만들기 ]


RecyclerView를 만들 때 xml을 이용하여 각 아이템을 만들어주었던 것 처럼 Compose를 이용해 아이템을 만들어주었다.
Column을 이용하여 만들었고 파라미터로 필요한 데이터들을 넣어주었다.
[ List를 구현하는 Composable함수 만들기 ]

가로로 나열되는 리스트를 구현해야하기 때문에 Row, 세로의 경우에는 Column을 이용해야한다.
LazyRow는 화면에 보이는 부분만 렌더링을 한다고 장점이 있어 리스트를 구현할 때는 LazyRow, LazyColumn을 이용하였다.
아이템간 간격은 horizontalArrangement 속성에 Arragment의 spacedBy속성을 지정해주면서 띄워줄 수 있다.
spacedBy()함수 안에 Aligment.CenterHorizontally가 파라미터로 들어가 있는 것을 볼 수 있는데,
Row안에 있는 아이템들을 중앙정렬 하기 위해 넣어준 것이다.
LazyRow, LazyColumn에는 item(), items(), itemsIndexed() 메서드가 있다.
item은 LazyRow, LazyColumn 내부에 컴포저블을 직접 넣을 때 사용하고, items는 반복되는 컴포저블을 넣고 싶을 때 사용하면 된다.
itemCount의 인자로는 해당 index에 해당하는 값을 방출하여, 각 아이템별 데이터를 지정해줄 수가 있다.
itemsIndexed는 itemCount의 인자로 Index와 해당 값이 모두 방출한다.
(Collection함수의 forEachIndexed와 이름도 방출되는 값도 비슷하다.)

- 최종적으로 RoundedCornerShape을 적용한 컴포저블

[ 데이터의 변경에 따른 UI업데이트 ]

Jetpack Compose를 이용하기 전에는 LiveData의 observe() 메서드를 이용하여 데이터의 변경을 관찰하고 UI를 업데이트 하였다.
컴포즈에서 조금 달라진게 있다면 observeAsState를 이용한다는 것이다.
observeAsState는 LiveData를 관찰하면서 LiveData가 변경될 때마다 State<T> 객체를 반환한다.
Compose에서 직접적으로 사용할 수 있는 observable타입이기도 하다.
이 함수는 LiveData가 Composition되는 동안에만 관찰한다.
[ 최종 완성 ]

모든 뷰를 ComposeView로 바꾸고 이어서 xml도 완전히 바로 제거해보았다.
아직은 ConstraintLayout에 매우 적응이 되어있어서 어색한 감이 있다.
그래도 리스트를 만들거나 하는 부분들이 매우 편리해졌다. 적응되면 퍼포먼스가 매우 올라갈 것 같다.
'Android' 카테고리의 다른 글
| Architecture Patterns (MVC, MVP, MVVM) (0) | 2022.08.16 |
|---|---|
| [Jetpack Compose] State (0) | 2022.04.22 |
| [Android] Fragment간 데이터 공유(Navigation, SafeArgs) (0) | 2021.05.07 |
| [Android] Dependency kotlin 코드로 관리하기(buildSrc) (0) | 2021.04.09 |
| [Android] Navigation Backstack Controll and Pass Data (0) | 2021.04.06 |