이전 전략

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

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() 메서드가 있습니다.

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

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

기존 화면에 새 기능 추가

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

추가하는 새 기능이 기존 화면의 일부인 경우 기존 뷰 기반 화면에서 Compose를 사용할 수도 있습니다. 이렇게 하려면 다른 뷰와 마찬가지로 뷰 계층 구조에 ComposeView를 추가합니다.

예를 들어 LinearLayout에 하위 뷰를 추가한다고 가정해 보겠습니다. 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/text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" />

  <androidx.compose.ui.platform.ComposeView
      android:id="@+id/compose_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />
</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.headlineMedium
        )
        Text(
            text = stringResource(R.string.subtitle),
            style = MaterialTheme.typography.headlineSmall
        )
        Text(
            text = stringResource(R.string.body),
            style = MaterialTheme.typography.bodyMedium
        )
        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 구성요소 삭제

모든 프래그먼트를 삭제하고 상응하는 화면 수준 컴포저블로 대체할 수 있게 되면 Navigation Compose로 이전할 수 있습니다. 화면 수준 컴포저블은 Compose 및 뷰 콘텐츠의 조합을 포함할 수 있지만, Navigation Compose 이전을 사용 설정하려면 모든 탐색 대상이 컴포저블이어야 합니다. 그때까지는 혼합 뷰 및 Compose 코드베이스에서 프래그먼트 기반 탐색 구성요소를 계속 사용해야 합니다. 자세한 내용은 Jetpack Navigation을 Navigation Compose로 이전을 참고하세요.

추가 리소스

기존 뷰 기반 앱을 Compose로 이전하는 방법을 자세히 알아보려면 다음 추가 리소스를 참고하세요.

다음 단계

지금까지 기존 뷰 기반 앱을 이전하는 데 활용할 수 있는 전략을 알아봤습니다. 자세한 내용은 상호 운용성 API를 참고하세요.