사실 개인적으로 Compose 를 공부해보려는 시도가 처음은 아니다. 작년 12월에 개인 회고를 하며 Compose 경험하기
를 목표로 잡았었고, 실제 이번 연도 언젠가 stable
버전이 나왔다는 소식을 들어 그 때 Compose 를 살짝 맛보려 했었다.
하지만 업무와 먼저 해야될 일들로 인해 마음먹은 지 1~2일도 안 되어 포기했고, 지금도 벌려놓은 개인 일정들로 인해 Compose 프로젝트를 해볼 생각을 못하고 어느덧 12월을 마주하게 되었다.
그러던 찰나 Android Studio 정식 버전에서 Compose 기반의 프로젝트를 생성할 수 있는 걸 다시 보게 되었다. 12월도 가까워지고 이 내용을 다시 보니 개인의 최소한의 속죄(?)와 양심을 생각해서(...) 기본적으로 생성되는 Compose 프로젝트를 분석해보는 시간이라도 가져야겠다는 생각이 생겨 이 포스트를 작성하게 되었다.
자신감 제로의 상태이지만 열정 만땅으로 일단 시작해본다. 내용을 작성하면 서 코드랩 또한 참고하였다.
먼저 프로젝트 생성은 Compose 기반 프로젝트를 선택하면 된다.
이해가 안될수도 있어 사진 한 장을 아래 첨부한다.
그러면 우리는 아래의 코드를 보게 된다.
잠시 기다리면 평소와 같이 MainActivity.kt
코드를 마주하게 된다.
이전과 차이가 있다면, xml 이 없다. (코드는 분석 단계에서 언급할 예정이다.)
갑자기 에러가 발생해요
갑자기 이런 류의 에러가 발생할 수 있다.
앞선Compose 적용기
포스트에 언급했다시피 컴포즈는 Kotlin version (1.5.31), Android Gradle Plugin (7.0.0), minSdkVersion (21) 을 맞춰주어야 한다. (의심된다면 이 링크를 보라)
필자의 경우에는 gradle JDK 설정과 compileOptions, kotlinOptions 의 Java, JVM 설정을 11로 바꾸었다.
위의 요구사항을 맞추고 빌드에 성공하여 아래 화면을 본다면 성공이다.
조금은 멋 없지만, 예쁘게 하는 건 이 포스트의 목적이 아니므로 바로 분석으로 들어간다.
일단 기존과 다르게 하나의 언어로만 Activity 가 만들어진다.
그런데 주목할 건 단순히 Activity 에 대해서만 하나의 언어가 아니라는 것이다.
파일을 분석하다보면 ui.Theme
라는 패키지가 보인다.
거기에는 색상값, 테마, 기존의 selector drawable 등 다양한 리소스 대체물들이 보인다.
그리고 실제 아래와 같이 적용하면 우리는 Teal200
색상이 적용된 텍스트를 만날 수 있다.
스크린샷은 따로 넣지 않겠다.
기존에 사용해왔던 xml 지식을 이젠 활용 못한다는 아쉬움(?)이 있지만
Kotlin 순도 100% 로 안드로이드 프로젝트를 만들기 위해선 어쩔 수 없다는 생각이 든다.
package kr.co.compose
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import kr.co.compose.ui.theme.ComposeTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
ComposeTheme {
Greeting("Android")
}
}
Activity 에 대한 코드는 이 내용밖에 없다고 했으므로 이 코드를 이제 분석해보자
savedInstanceState
를 파라미터로 받는 건 똑같다.
다만 setContentView
가 보이지 않는데 이건 뭘로 대체가 되었는지 대충봐도 알 수 있다.
setContent {
ComposeTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
// ...
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!", style = TextStyle(color = Teal200))
}
setContent 안의 내용을 별다른 개념 없이 { ... }
을 "설정한다"로 이해하고,
함수의 개념대로만 이해하면 아래와 같이 이야기할 수 있다.
MaterialTheme.colors.background
배경 색상을 가지는 Surface 를 설정한다.확실하게 느낀 건 이 Activity 에 무엇을 설정했고 사용하는지 한 눈에 이해된다는 것이다.
(ComposeTheme 를 설정했고, Text 를 가지고 있으며 텍스트 색상은 Teal200 이다.)
이전의 Kotlin 파일에 1줄짜리 setContentView 를 제공하고, style.xml, activity_main.xml 를 봐야했던 과거와 달리, Kotlin 파일에 View 의 이야기가 코드로 드러난 모습이다.
타고 들어가면 ui.theme
패키지에서 Theme.kt 에 이미 선언되어 있는 것을 확인할 수 있다.
@Composable
fun ComposeTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
@Composable
어노테이션을 가진 함수로 구현되어 있다.
다크 테마 여부를 체크하여 이에 맞는 색상 테마, 폰트 등을 설정하는 것을 확인할 수 있다.
기존의 styles.xml
을 생각하면 편할 것 같다.
Surface 하고 MaterialTheme 는 Google 에서 만든 Material Design 과 관련된 개념이라고 한다.
시각적으로 관련되는 방식 및 그림자를 드리우는 방식 등에 영향을 주며 이것 또한 @Composable
어노테이션을 가진 함수로 구현되어 있다.
Text 함수를 가지고 있는 @Composable
함수이며 Text 를 설정해주는 것 같이 보인다.
(참고로 Text 또한 @Composable
함수이다.)
여기까지 오면 공통된 단어가 계속 보일 것이다. @Composable
어노테이션을 가진 함수
이 함수의 정체는 무엇일까?
코드랩에 보면 이런 내용이 있다.
Compose App 은 Composable 함수로 이루어집니다.
Composable 은 다른 Composable 함수를 호출할 수 있는 단순한 함수일 뿐입니다.
새 UI 구성 요소를 만드는 데 필요한 건 함수 뿐이며, Composable 어노테이션은 UI 를 업데이트하고 유지할 수 있도록 Compose 에 지시합니다. Compose 를 사용하면 코드를 작은 뭉치로 구조화할 수 있고, Composable 함수는 줄여서 Composable 이라고도 합니다.
정리해보면 Composable 어노테이션 함수는 UI 이다.
그러면서 반환값이 없기 때문에, UI 값을 리턴 받아 다른 위치에서 활용될 가능성은 없다.
그 개념으로 이해를 해보면 Greeting 함수는 일종의 UI
이며, Greeting 내에서는 Text UI
를 가진다고 표현할 수 있다.
우리는 위 onCreate() 분석을 통해, Composable 함수를 선언하여 UI 를 설정하고, UI 와 관련된 설정 (ex. 텍스트 색상 설정) 은 오로지 Composable 함수 선언부에서만 이루어진다는 것을 확인할 수 있다.
onCreate 밑을 보면 이런 함수가 있다.
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
ComposeTheme {
Greeting("Android")
}
}
내용을 보면 Composable 함수인데, onCreate 의 setContent 와 비슷한 내용이 적혀있다.
왜 사용하는 걸까? 정의를 보면 바로 알 수 있다.
@PreView 는 Composable 함수에 적용할 수 있으며, Android Studio Preview 를 보여주기 위해 활용됩니다.
정리하면 IDE 에서 UI 를 보기 위해 사용된다. 실제 보면 아래 우측과 같이 preview 를 볼 수 있다.
개인적으로 코드가 비슷하고 중복을 없애도 문제없을 것 같아 보인다.
우리가 배운 Composable 개념을 활용해 이렇게 하면 안될까?
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MainView()
}
}
}
@Composable
fun MainView() {
ComposeTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!", style = TextStyle(color = Teal200))
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MainView()
}
MainView
라는 Composable 함수를 만들어 setContent 와 Preview 에서 사용되는 중복 코드를 줄였다. 이렇게 해도 결과는 동일하다.
PreView 를 여러개 사용할 수 있다.
아래와 같이 DefaultPreView2 를 선언하고 빌드하면 PreView 가 2개 보인다.
오직 MainActivity 만 얕게 분석해보았고 이에 대한 실험만 해보았는데도 Compose 의 장점은 명확히 보였다.
100%
에 가까워진 Kotlin 코드선언형 UI
로 인한 직관성 향상코드 수정으로 인한 영향 최소화
여기에 MVVM 이나 MVP 를 적용시킨다면 xml 에 kotlin 을 강제 적용하여 고통받았던 에피소드는 이제 없어질 것이다. (함수형 변수 넣을 때 맨날 고통받았던 기억....) 더불어 View 가 수동적
이 되어야 하는 MVVM 의 경우엔, 3번 요인으로 인해 더욱 아키텍처 개념을 확고하게 할 수 있을 것 같다.
장점을 보고 관련된 레퍼런스들을 깊게 deep Dive
해야겠다는 생각이 들었던 분석 시간이었다.