迁移策略

如果您有一个现有的基于 View 的应用,您可能不希望立即重写其整个 UI。此页面将帮助您将新的 Compose 组件添加到现有应用中。要开始在应用中使用 Compose,请参阅为现有应用设置 Compose

Jetpack Compose 从一开始就设计了与 View 的互操作性。此功能意味着您可以在迁移现有的基于 View 的应用到 Compose 的同时,仍然能够构建新的功能。要迁移到 Compose,我们建议进行增量迁移,其中 Compose 和 View 在您的代码库中共存,直到您的应用完全迁移到 Compose。

The stages of a View-based app’s migration to Compose
图 1. 基于 View 的应用迁移到 Compose 的阶段

要将您的应用迁移到 Compose,请按照以下步骤操作

  1. 使用 Compose 构建新的屏幕。
  2. 在构建功能时,识别可重用的元素并开始创建常用 UI 组件的库。
  3. 一次替换一个现有功能的屏幕。

使用 Compose 构建新屏幕

使用 Compose 构建包含整个屏幕的新功能是推动您采用 Compose 的最佳方式。使用此策略,您可以在添加功能并利用Compose 的优势的同时,仍然满足您公司的业务需求。

A new screen written in Compose
图 2. 使用 Compose 编写的新的屏幕

当您使用 Compose 在现有应用中构建新屏幕时,您仍然受应用架构的限制。如果您正在使用 Fragment 和 Navigation 组件,则必须创建一个新的 Fragment 并将其内容放在 Compose 中。

要在 Fragment 中使用 Compose,请在 Fragment 的onCreateView()生命周期方法中返回一个ComposeViewComposeView有一个setContent()方法,您可以在其中提供一个可组合函数。

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

请参阅Fragment 中的 ComposeView以了解更多信息。

在现有屏幕中添加新功能

An existing screen with mixed Views and Compose
图 3. 混合使用 View 和 Compose 的现有屏幕

如果您要添加的新功能是现有屏幕的一部分,您也可以在基于 View 的现有屏幕中使用 Compose。为此,将ComposeView添加到 View 层次结构中,就像任何其他 View 一样。

例如,假设您想将子 View 添加到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>

一旦 View 已膨胀,您可以在以后引用层次结构中的ComposeView并调用setContent()

要了解有关ComposeView的更多信息,请查看互操作性 API

构建常用 UI 组件的库

在使用 Compose 构建功能时,您会很快意识到您最终会构建一个组件库。创建常用 UI 组件的库可以让您在应用中拥有这些组件的单一事实来源并促进重用。您构建的功能随后可以依赖此库。如果您正在使用 Compose 构建自定义设计系统,则此技术特别有用。

根据应用的大小,此库可以是单独的包、模块或库模块。有关在应用中组织模块的更多信息,请查看Android 应用模块化指南

使用 Compose 替换现有功能

除了使用 Compose 构建新功能外,您还希望逐步将应用中的现有功能迁移到 Compose,以利用 Compose 的优势。

使您的应用仅使用 Compose 可以加快您的开发速度,并减少应用的 APK 大小和构建时间。请参阅比较 Compose 和 View 的性能以了解更多信息。

简单的屏幕

迁移现有功能到 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>

可以在 Compose 中用几行代码重写 XML 文件

@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))
        }
    }
}

混合 View 和 Compose 屏幕

已经包含一些 Compose 代码的屏幕是另一个适合完全迁移到 Compose 的候选对象。根据屏幕的复杂性,您可以将其完全迁移到 Compose,或者逐个部分进行迁移。如果屏幕在 UI 层次结构的子树中以 Compose 开始,则您将继续迁移 UI 元素,直到整个屏幕都在 Compose 中。此方法也称为自下而上方法。

Bottom-up approach of migrating a mixed Views and Compose UI to Compose
图 4. 将混合使用 View 和 Compose 的 UI 迁移到 Compose 的自下而上方法

移除 Fragment 和 Navigation 组件

一旦能够移除所有 Fragment 并替换为相应的屏幕级可组合项,您就可以迁移到Navigation Compose。屏幕级可组合项可以包含Compose 和 View 内容的混合,但所有导航目标必须是可组合项才能启用 Navigation Compose 迁移。在此之前,您应该继续在混合 View 和 Compose 代码库中使用基于 Fragment 的 Navigation 组件。请参阅将 Jetpack Navigation 迁移到 Navigation Compose以了解更多信息。

其他资源

查看以下其他资源以了解有关将现有的基于 View 的应用迁移到 Compose 的更多信息

后续步骤

现在您已经了解了迁移现有基于 View 的应用的策略,请探索互操作性 API以了解更多信息。