Composition 생성하기
Android의 경우 ViewGroup이나 setContent 호출을 통해 새로운 composition을 생성할 수 있다.
internal fun ViewGroup.setContent(
parent: CompositionContext,
contnet: @Composable () -> Unit
): Composition {
val composeView = ...
return doSetContent(composeView, parent, content)
}
private fun doSetContent(
owner: AndroidComposeView,
parent: CompositionContext,
contnet: @Composable () -> Unit
): Composition {
val original = Composition(UiApplier(own.root), parent)
val wrapped = owner.view.getTag(R.id.wrapped_composition_tag)
as? WrappedComposition ?: WrappedComposition(owner, original).also {
owner.view.setTag(R.id.wrpped_composition_tag, it)
}
wrapped.setContent(content)
return wrapped
}
위 코드에서 WrappedComposition은 Composition을 AndroidComposeView에 연결하는 방법을 알고 있는 데코레이터로써 안드로이드의 Context에 대한 정보를 Composition에 CompositionLocal이라는 형태로 제공한다.
이를 통해 모든 Composable 함수 내부에서 기존의 안드로이드와 관련된 것들이 암시적으로 사용 가능하다.
Composition()에 전달된 UiApplier는 트리의 루트 LayoutNode를 가르킴으로써 명시적으로 클라리언트단의 라이브러리가 Applier의 구현을 선택할 책임이 있다.
마지막으로 composition.setContent(content)가 호출되어 Composition의 속성이 최종적으로 생성(혹은 업데이트)되는 것의 구현을 살펴볼 수 있다.
Composition을 생성하는 또 다른 좋은 예로는 Compose UI의 일부이면서 화면에 벡터를 그리는데 사용되는 VectorPainter가 있다.
@Composable
internal fun RenderVector(
name: String,
viewportWidth: Float,
viewportHeight: Float,
content: @Composable(viewportWidth: Float, viewportHeight: Float) -> Unit
) {
val composition = composeVector(rememberCompositionContext(), content)
DisposableEffect(composition) {
onDispose {
compostion.dispose()
}
}
}
private fun composeVector(
parent: CompositionContext,
composable: @Composable (viewportWidth: Float, viewportHeight: Float) -> Unit
): Composition {
val existing = composition
val next = if (existing == null || existing.isDisposed) {
Composition(VectorApplier(vector.root), parent)
} else {
existing
}
composition = next
next.setContent {
composable(vector.viewportWidth, vector.viewportHeight)
}
return next
}
위 코드를 살펴보면 Composition이 생성될 때마다 상위의 CompositionContext가 전달될 수 있다.
상위 context가 존재하는 경우 새로운 composition은 기존의 composition에 연결하는데 사용되며 invalidation 및 CompositionLocal은 composition 전체에서 동일한 것으로 취급될 수 있다.
Composition을 생성할 때 recomposition context를 전달하는 것도 가능한데, 이를 통해 변경 사항을 적용하기 위해 Applier에서 사용하는 CoroutineContext가 된다.
만약 전달하지 않는 경우엔 기본적으로 Recomposer가 제공하는 EmptyCoroutineContet가 적용된다.
Composition이 더 이상 필요하지 않을 경우엔 composition.dispose() 를 통해 폐기되어야 하며, 이 단계는 해당 UI가 더 이상 사용되지 않을 때를 의미한다.
'Android' 카테고리의 다른 글
[Android] Compose 런타임 - (12) (0) | 2024.12.12 |
---|---|
[Android] Compose 런타임 - (11) (0) | 2024.12.11 |
[Android] Compose 런타임 - (9) (0) | 2024.12.05 |
[Android] Compose 런타임 - (8) (0) | 2024.12.04 |
[Android] Compose 런타임 - (7) (0) | 2024.12.03 |