이전 전략

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

뷰 기반의 UI를 사용하는 앱의 경우 전체 UI를 한 번에 재작성하지 않는 것이 좋습니다. 이 페이지에서는 새 Compose 요소를 기존 UI에 추가하는 방법을 설명합니다.

Jetpack Compose는 처음부터 뷰 상호 운용성을 고려하여 설계되었습니다. 이 기능을 사용하면 기존 뷰 기반 앱을 Compose로 이전하면서도 계속 새 기능을 빌드할 수 있습니다. Compose로 이전하려면 앱이 Compose에 완전히 이전될 때까지 Compose와 뷰가 코드베이스에 공존하는 증분 이전을 사용하는 것이 좋습니다.

뷰 기반 앱의 Compose 이전 단계
그림 1. 뷰 기반 앱의 Compose 이전 단계

앱을 Compose로 이전하려면 다음 단계를 따르세요.

  1. Compose를 사용하여 새로운 기능을 빌드합니다.
  2. 기능을 빌드하면서 재사용 가능한 요소를 식별하고 공통 UI 구성요소의 라이브러리를 만들기 시작합니다.
  3. 기존 기능을 한 번에 한 화면씩 대체합니다.

Compose를 사용하여 새로운 기능 빌드

Compose를 사용하여 새로운 기능을 빌드하는 것은 Compose 채택을 유도하는 가장 좋은 방법입니다. 이 전략을 사용하면 기능을 추가하고 Compose의 이점을 활용하면서 회사의 비즈니스 요구사항도 충족할 수 있습니다.

새 화면

Compose로 작성된 새 화면
그림 2. Compose로 작성된 새 화면

Compose를 사용하여 기존 앱에 새 기능을 빌드하는 경우 여전히 앱 아키텍처의 제약을 받으며 작업하게 됩니다. 프래그먼트와 Navigation 구성요소를 사용 중이며 빌드하고 있는 기능이 전체 화면을 포함하는 경우 새 프래그먼트를 만들어야 하지만 그 콘텐츠는 Compose에 있습니다.

프래그먼트에서 Compose를 사용하려면 프래그먼트의 onCreateView() 수명 주기 메서드에서 ComposeView를 반환합니다. ComposeView에는 구성 가능한 함수를 제공할 수 있는 setContent() 메서드가 있습니다.

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment

class NewFeatureFragment : Fragment() {
   override fun onCreateView(
       inflater: LayoutInflater,
       container: ViewGroup?,
       savedInstanceState: Bundle?
   ): View {
       return ComposeView(requireContext()).apply {
           setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed)
           setContent {
               NewFeatureScreen()
           }
       }
   }
}

자세한 내용은 프래그먼트의 ComposeView를 참고하세요.

기존 화면

뷰와 Compose가 혼합된 기존 화면
그림 3. 뷰와 Compose가 혼합된 기존 화면

새 기능이 기존 화면의 일부가 된다면 다른 뷰와 마찬가지로 UI 계층 구조에 ComposeView를 추가할 수 있습니다.

예를 들어 LinearLayout에 하위 뷰를 추가한다고 가정해 보겠습니다. XML에서 다음과 같이 하면 됩니다.

<LinearLayout ...>

  <Button ... />

  <TextView ... />

  <androidx.compose.ui.platform.ComposeView
    android:id="@+id/compose_view" ... />

</LinearLayout>

뷰가 확장되면 나중에 계층 구조에서 ComposeView를 참조하고 setContent()를 호출할 수 있습니다.

ComposeView에 관한 자세한 내용은 상호 운용성 API를 확인하세요.

공통 UI 구성요소의 라이브러리 빌드

Compose를 사용하여 기능을 빌드하다 보면 결국 구성요소 라이브러리를 빌드하게 됩니다. 공통 UI 구성요소 라이브러리를 만들면 앱에 이러한 구성요소의 단일 정보 소스를 확보하고 재사용성을 높일 수 있습니다. 그러면 빌드하는 기능이 이 라이브러리에 종속될 수 있습니다. 이 기법은 Compose에서 맞춤 디자인 시스템을 빌드하는 경우에 특히 유용합니다.

앱 크기에 따라 이 라이브러리는 별도의 패키지, 모듈 또는 라이브러리 모듈일 수 있습니다. 앱에서 모듈을 구성하는 방법에 관한 자세한 내용은 Android 앱 모듈화 가이드를 참고하세요.

기존 기능을 Compose로 교체

Compose를 사용하여 새 기능을 빌드하는 것 외에도 Compose를 활용하려면 앱의 기존 기능을 점진적으로 이전하는 것이 좋습니다.

앱을 Compose 전용으로 만들면 개발을 가속화하고 앱의 APK 크기와 빌드 시간을 줄일 수 있습니다. 자세한 내용은 Compose의 개발자 에르고노믹스를 참고하세요.

간단한 화면

기존 기능을 Compose로 이전할 때 가장 먼저 살펴봐야 할 곳은 간단한 화면입니다. 간단한 화면은 시작 화면이나 확인 화면, UI에 표시되는 데이터가 비교적 정적인 설정 화면일 수 있습니다.

다음 XML 파일을 살펴보세요.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

 <TextView
   android:id="@+id/title_text"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="@string/title"
     android:textAppearance="?attr/textAppearanceHeadline2" />

 <TextView
     android:id="@+id/subtitle_text"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="@string/subtitle"
     android:textAppearance="?attr/textAppearanceHeadline6" />

 <TextView
     android:id="@+id/body_text"
     android:layout_width="wrap_content"
     android:layout_height="0dp"
     android:layout_weight="1"
     android:text="@string/body"
     android:textAppearance="?attr/textAppearanceBody1" />

 <Button
     android:id="@+id/confirm_button"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="@string/confirm"/>

</LinearLayout>

XML 파일은 Compose에서 몇 줄로 다시 작성할 수 있습니다.

@Composable
fun SimpleScreen() {
    Column(Modifier.fillMaxSize()) {
        Text(
            text = stringResource(R.string.title),
            style = MaterialTheme.typography.h2
        )
        Text(
            text = stringResource(R.string.subtitle),
            style = MaterialTheme.typography.h6
        )
        Text(
            text = stringResource(R.string.body),
            style = MaterialTheme.typography.body1
        )
        Spacer(modifier = Modifier.weight(1f))
        Button(onClick = { /* Handle click */ }, Modifier.fillMaxWidth()) {
            Text(text = stringResource(R.string.confirm))
        }
    }
}

뷰와 Compose가 혼합된 화면

이미 Compose 코드가 일부 포함되어 있는 화면도 Compose로 완전히 이전하기 좋은 대상입니다. 화면의 복잡성에 따라 전체를 Compose로 이전하거나 하나씩 이전할 수 있습니다. 화면이 UI 계층 구조의 하위 트리에서 Compose로 시작했다면 전체 화면이 Compose로 이전될 때까지 UI 요소를 계속 이전합니다. 이 접근 방식을 상향식 접근 방식이라고도 합니다.

뷰와 Compose가 혼합된 UI를 Compose로 이전하는 상향식 접근 방식
그림 4. 뷰와 Compose가 혼합된 UI를 Compose로 이전하는 상향식 접근 방식

프래그먼트 및 Navigation 구성요소 삭제

앱의 모든 UI가 Compose에 있으면 앱에서 프래그먼트를 사용해도 이점이 거의 없습니다. 이 상황에 도달하면 프래그먼트를 완전히 삭제하고 대신 Navigation Compose에서 구동하는 화면 수준 컴포저블로 대체할 수 있습니다.

자세한 내용은 Compose를 통해 이동을 참고하세요.

다음 단계

앱에 Compose를 추가하는 방법을 바로 알아보려면 앱에 Jetpack Compose 추가를 참고하세요. 다음 리소스도 확인해 보세요.