보일러플레이트 코드 없이 리컴포지션 추적하기

어떠한 코드 추가 없이 Jetpack Compose 리컴포지션 추적

Ji Sungbin
6 min readMar 4, 2024

[View in English]

Photo by Matias Luge on Unsplash

Android Studio의 기능 중 Layout Inspector를 사용하면 리컴포지션 횟수와, 리컴포지션을 건너뛴 횟수를 알 수 있습니다. 하지만 어느 필드가 변경되어 리컴포지션이 되었는지 알 수 없고, 큰 프로젝트라면 Layout Inspector가 때때로 동작하지 않거나 화면 갱신까지 지연이 생기는 경우가 있습니다.

Layout Inspector를 사용하면서 위와 같은 불편함을 겪었고, 이를 해결하기 위해 Layout Inspector의 리컴포지션 추적 기능만 별도로 분리하여 플러그인으로 개발하였습니다.

ComposeInvestigator

개발한 플러그인은 오픈소스이며, ComposeInvestigator라고 부릅니다.

Now In Android를 예시 프로젝트로 사용하여 소개하겠습니다. 사용 방법은 아주 간단합니다. Gradle 플러그인 단 한 줄만 추가해 주면 됩니다.

plugins {
id("land.sungbin.composeinvestigator") version "1.5.10-0.1.0"
}

이후 앱을 실행하여 로그켓을 확인해 봅시다.

ComposeInvestigator로 검색했을 때 다양한 로그가 출력된 걸 볼 수 있습니다.

ComposeInvestigator는 총 네 가지 종류의 로그를 출력합니다.

1. 리컴포지션 요청

리컴포지션이 요청된 경우입니다. 컴포즈는 내부적으로 리컴포지션이 요청된 경우 “리컴포지션 진행” 또는 “리컴포지션 스킵”의 결과로 이어집니다.

ComposeInvestigator     The 'ForYouRoute' composable has been invalidated.
Processed(reason=[Invalidate] An invalidation has been requested for the current composable scope. The state value in the body of that composable function has most likely changed.

2. 리컴포지션 진행

리컴포지션이 실제로 진행된 경우입니다. 이 경우는 리컴포지션된 컴포저블의 어떤 인자가 변경되었는지 같이 출력됩니다.

3. 상태 변수 값 변경

리컴포지션이 실제로 진행됐을 때 원인 파악을 돕기 위해, State 변수의 값이 변경되었을 때도 출력됩니다.

ComposeInvestigator     The state of 'searchQuery' inside 'SearchRoute' composable has changed. previousValue=Hello, Worl, newValue=Hello, World

4. 리컴포지션 스킵

리컴포지션이 요청됐지만, 변경된 요소가 없어 스킵된 경우입니다.

이 외에도 다양한 런타임 함수를 사용하여 더 많은 문제를 해결하거나, 각각 상황별로 실행될 콜백을 등록할 수 있습니다.

예를 들어 동일한 이름의 컴포저블이 여러 개 있을때는, 로그켓에서 어떠한 컴포저블을 나타내는지 알아차리기 쉽지 않습니다.

이럴 때 currentComposableInvalidationTracker.currentComposableName API를 사용하여 임시로 컴포저블의 이름을 변경할 수 있습니다. 이러한 변경은 오직 ComposeInvestigator의 로그에서만 유효합니다.

또한 동일한 컴포저블이 여러 파일에서 사용됐을 경우도, 로그켓에서 어떤 파일의 컴포저블을 나타내는지 알아차리기 쉽지 않습니다. 이 경우에는 리컴포지션 추적 로깅 포멧을 변경하여 컴포저블 콜스택을 로그에 추가함으로써 해결할 수 있습니다.

ComposeInvestigatorConfig.invalidationLogger = ComposableInvalidationLogger { callstack, composable, type ->
Log.d(
"ComposeInvestigator",
"The '${composable.name}' composable has been invalidated.\n(${callstack.joinToString(separator = " -> ")})\n$type"
)
}

이 밖에 더 많은 런타임 API 활용은 ComposeInvestigator의 공식 문서에서 확인하실 수 있습니다. (혹시나 내부가 궁금하다면 내부 원리도 공식 문서에서 확인하실 수 있습니다)

ComposeInvestigator 프로젝트를 진행하면서 Jetpack Compose의 리컴포지션 동작을 확실히 이해할 수 있었습니다. 이는 별도의 게시글로 작성될 예정이고, 컴포즈 내부의 리컴포지션 구현 코드는 이전에 작성한 “Jetpack Compose 런타임에서 일어나는 마법 완전히 파헤치기 — Invalidation” 게시글에서 확인할 수 있습니다.

ComposeInvestigator가 유용하게 쓰일 수 있길 바랍니다. 감사합니다.

--

--

Ji Sungbin

Experience Engineers for us. I love development that creates references.