앱에 Jetpack Compose 추가

기존 프로젝트에서 Jetpack Compose를 사용하려면 필요한 설정 및 종속 항목으로 프로젝트를 구성해야 합니다.

개발 환경 설정

정확한 Android 스튜디오 버전 설치

Jetpack Compose로 최적의 환경에서 개발하려면 Android 스튜디오 Arctic Fox를 다운로드하고 Android 스튜디오 버전에 맞는 Android Gradle 플러그인을 구성해야 합니다.

buildscript {
    ...
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.0"
        ...
    }
}

Kotlin 구성

프로젝트에서 Kotlin 1.5.21을 사용하는지 확인합니다.

plugins {
    id 'org.jetbrains.kotlin:android' version '1.5.21'
}

Gradle 구성

아래와 같이 앱의 최소 API 수준을 21 이상으로 설정하고 앱의 build.gradle 파일에서 Jetpack Compose를 사용 설정해야 합니다. Kotlin 컴파일러 플러그인의 버전도 설정합니다.

android {
    defaultConfig {
        ...
        minSdkVersion 21
    }

    buildFeatures {
        // Enables Jetpack Compose for this module
        compose true
    }
    ...

    // Set both the Java and Kotlin compilers to target Java 8.
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }

    composeOptions {
        kotlinCompilerExtensionVersion '1.0.1'
    }
}

Jetpack Compose 도구 키트 종속 항목 추가

아래와 같이 앱의 build.gradle 파일에 Jetpack Compose 도구 키트 종속 항목을 포함하세요.

dependencies {
    // Integration with activities
    implementation 'androidx.activity:activity-compose:1.3.1'
    // Compose Material Design
    implementation 'androidx.compose.material:material:1.0.1'
    // Animations
    implementation 'androidx.compose.animation:animation:1.0.1'
    // Tooling support (Previews, etc.)
    implementation 'androidx.compose.ui:ui-tooling:1.0.1'
    // Integration with ViewModels
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
    // UI Tests
    androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.0.1'
}

Compose에서 뷰 테마 재사용

Compose를 프로젝트에 방금 추가한 경우, Compose에서 고유 머티리얼 테마를 처음부터 재작성하는 대신 뷰 시스템에 사용할 수 있는 테마를 Compose에서 상속할 수 있습니다.

Android 앱에서 MDC 라이브러리를 사용하는 경우, MDC Compose 테마 어댑터 라이브러리를 통해 기존 뷰 기반 테마의 색상, 글꼴 및 모양 테마를 컴포저블에 쉽게 재사용할 수 있습니다. 이렇게 하려면 MdcTheme API를 사용하면 됩니다.

AppCompat XML 테마를 대신 사용하고 있다면 AppCompatTheme API가 포함된 AppCompat Compose Theme Adapter를 사용하세요.

아래와 같이 앱의 build.gradle 파일에 필요한 종속 항목을 포함하세요.

dependencies {
    // When using a MDC theme
    implementation "com.google.android.material:compose-theme-adapter:1.0.1"

    // When using a AppCompat theme
    implementation "com.google.accompanist:accompanist-appcompat-theme:0.16.0"
}

Compose로 이전 시작

애플리케이션에서 사용자 인사말 텍스트를 Jetpack Compose로 이전한다고 가정해 보겠습니다. XML 레이아웃에 다음과 같은 콘텐츠가 있을 수 있습니다.

<...>
    <!-- Other content -->

    <TextView
        android:id="@+id/greeting"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/margin_small"
        android:layout_marginEnd="@dimen/margin_small"
        android:gravity="center_horizontal"
        android:text="@string/greeting"
        android:textAppearance="?attr/textAppearanceHeadline5"
        ... />
</...>

Compose로 이전하려면 ViewComposeView로 대체하고 레이아웃 매개변수와 id는 동일하게 유지하면 됩니다.

<...>
    <!-- Other content -->

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/greeting"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</...>

그런 다음 XML 레이아웃을 사용하는 Activity 또는 Fragment에서 ComposeView를 가져오고 이 요소에 Compose 콘텐츠를 추가하기 위한 setContent 메서드를 호출하면 됩니다.

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...

        val greeting = findViewById<ComposeView>(R.id.greeting)
        greeting.setContent {
            MdcTheme { // or AppCompatTheme
                Greeting()
            }
        }
    }
}

@Composable
private fun Greeting() {
    Text(
        text = stringResource(R.string.greeting),
        style = MaterialTheme.typography.h5,
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = dimensionResource(R.dimen.margin_small))
            .wrapContentWidth(Alignment.CenterHorizontally)
    )
}

ComposeView 및 기타 상호 운용성 API에 관한 자세한 내용은 상호 운용성 API 가이드를 확인하세요. Compose의 stringResource, dimensionResource 및 기타 리소스 API에 관해 자세히 알아보려면 Compose의 리소스 가이드를 확인하세요.

중첩 UI 테스트

앱의 일부를 Compose로 이전한 후 어떤 것도 손상되지 않았는지 확인하는 테스트가 중요합니다.

활동 또는 프래그먼트에 Compose를 사용한다면 ActivityScenarioRule을 사용하는 대신 ActivityScenarioRuleComposeTestRule과 통합하는 createAndroidComposeRule을 사용해야 합니다. 그러면 Compose와 View 코드를 동시에 테스트할 수 있습니다.

class MyActivityTest {
    @Rule
    @JvmField
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test
    fun testGreeting() {
        val greeting = InstrumentationRegistry.getInstrumentation()
            .targetContext.resources.getString(R.string.greeting)

        composeTestRule.onNodeWithText(greeting).assertIsDisplayed()
    }
}

테스트와 Espresso와의 상호 운용성에 관해 자세히 알아보려면 Compose 레이아웃 테스트 가이드를 확인하세요.

아키텍처에서 작성

Compose는 대부분의 앱 아키텍처를 지원하고 널리 사용되는 기타 여러 라이브러리와의 통합도 제공합니다. 따라서 앱에서 Compose 사용을 시작하려고 할 때 계층 구조의 다른 레이어를 변경할 필요가 없습니다.

다음 코드 스니펫은 Compose가 viewModel() 함수를 사용하여 아키텍처 구성요소 ViewModel과 작동하는 방식과 collectAsState()를 사용하여 Kotlin Flow에서 수집하는 방식을 보여줍니다.

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyScreen()
        }
    }
}

@Composable
private fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsState()
    when {
        uiState.isLoading -> { /* ... */ }
        uiState.isSuccess -> { /* ... */ }
        uiState.isError -> { /* ... */ }
    }
}

class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(MyScreenState.Loading)
    val uiState: StateFlow<MyScreenState> = _uiState
}

이미지 로드, Paging 또는 Hilt와 같은 그 외 통합에 관한 자세한 내용은 Compose 및 기타 라이브러리 가이드를 확인하세요.

앱에 탐색 구성요소를 사용하는 경우 'Compose를 통해 이동' 가이드의 상호 운용성 섹션을 확인하세요.

다음 단계

Compose에 관한 자세한 내용은 도움말 색인에서 확인할 수 있습니다. 앱에 Compose를 채택하는 방법에는 여러 가지가 있습니다. 자세한 내용은 앱에 Compose 채택 가이드를 참고하세요. 이 가이드는 다른 가이드(예: 기존 아키텍처에서 사용하는 Compose기존 UI에서 사용하는 Compose)와도 연결되어 있습니다.