Compose 与传统 View 互操作策略:分层解耦实战

By 孙越 · 平台工程师 • Published: 2025-10-28 • Updated: 2025-10-2813 min read

互操作多模块架构治理

大多数企业级应用都会经历较长的迁移窗口期,Compose 不可能一蹴而就。在并存阶段,我们需要构建清晰的互操作边界,确保宿主模块的生命周期、主题体系与性能指标不被破坏。

我们建议从“阅读型模块”切入,引入 `ComposeView` 作为桥接容器,并通过统一的 Design System Adapter 将颜色、排版、间距等设计令牌映射到 Compose `MaterialTheme`。

模块化拆分原则

  • 桥接层独立成模块:`ui-interop` 仅负责 View 与 Compose 的交互,避免业务模块直接依赖实现细节;
  • Compose 入口保持无状态:通过参数传递数据与回调,将状态托管在 ViewModel 或 UseCase 层;
  • 对外暴露稳定接口:使用 `@Stable` 数据结构作为边界契约,降低重组带来的 diff 噪音。
Note: 互操作模块需单独配置 R8 keep 规则,保留 `androidx.compose` 相关类,防止代码压缩阶段误删。

桥接层实现要点

如下示例展示了如何在 View 模块中安全托管 Compose,并同步宿主主题与生命周期。我们推荐使用 `ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed` 避免内存泄漏。

class ComposeInterstitial @JvmOverloads constructor(
     context: Context,
     attrs: AttributeSet? = null
 ) : FrameLayout(context, attrs) {

     private val composeView = ComposeView(context).apply {
         setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
     }

     init {
         addView(composeView)
     }

     fun render(state: InteropState, onAction: (InteropAction) -> Unit) {
         composeView.setContent {
             LegacyThemeAdapter {
                 InteropScreen(state = state, onAction = onAction)
             }
         }
     }
 }

 @Stable
data class InteropState(
     val title: String,
     val illustrations: ImmutableList<Illustration>
 )

监控与性能回归

互操作阶段的性能监控尤为关键。我们在 FrameMetricsAggregator 中记录新旧界面的首帧时间,并借助 `Choreographer.FrameCallback` 捕获掉帧,将指标写入 Grafana。

当 Compose 模块占比超过 60% 时,可考虑将 `ComposeView` 迁移为完全的 `Activity`/`Fragment` 层级,以减少额外的测量与布局成本。

← Back to Blog