[Android] Surface에서는 recomposition이 안돼요

유진·2025년 8월 8일
1

Android

목록 보기
7/8
post-thumbnail

Compose를 이용하면 component로 custom view를 자유자재로 만들 수 있다. material component를 재정의해서 쓸 수도 있으며, 아예 처음부터 만들 수도 있다. 이런 자유로운 뷰 구성이 Compose의 가장 큰 장점이라고 체감한다.

RadioButton 처럼 하나만 클릭되는 버튼들을 커스텀으로 제작하는 중 마주한 오류가 있다. 분명히 클릭 로그는 찍히는데, UI상으로 변화가 없다..!

이는 컴포넌트의 최상단이 Box가 아닌 Surface로 지정해서 생긴 문제였다. 좀 더 자세히 알아보자.

Surface의 내부 최적화에 따른 recomposition 누락

Compose의 Surface는 내부적으로 색상, elevation, 클릭 효과 등을 처리하면서 최적화를 수행한다.
이 과정에서 상태 변화가 있더라도 UI에 변화가 없다고 판단되면 draw를 생략하여 화면이 갱신되지 않을 수 있다.


Surface와 Box의 차이

Compose에서 SurfaceBox는 모두 UI를 구성하는 레이아웃 요소지만, 내부 작동 방식과 recomposition 최적화 처리에서 큰 차이를 보인다. 이번 사례에서 Surface는 상태 변화에 따라 UI가 눈에 보이게 변하지 않았으며, 그 이유는 아래와 같다.

Surface는 내부적으로 머티리얼 레이어 계층, 색상, 그림자, 클릭 등을 종합적으로 처리한다. 이 과정에서 재조합 최적화가 발생하여, 상태 변화가 시각적으로 드러나지 않을 수 있다.

반면, Box는 단순한 컨테이너로 동작하므로 상태 변화가 곧바로 시각적 변화로 이어진다.


Surface의 내부 동작

Surface는 단순한 박스가 아니라 다음과 같은 기능을 자동으로 포함한다.

기능설명
색상 블렌딩elevation, background color에 따라 색상이 자동으로 섞인다
그림자 처리머티리얼 스타일의 그림자(elevation)를 렌더링한다
Ripple 효과클릭 시 Ripple 효과를 기본으로 제공한다
ContentColor 제공내부의 Text, Icon 등에 LocalContentColor를 주입한다
CompositionLocal 변경내부적으로 LocalContentColor, LocalAbsoluteTonalElevation 등의 context 값을 변경한다

결과적으로

  • 많은 처리를 Compose 내부 composition scope에 위임한다.
  • 상태 변경에 따른 색상 변화가 명확하지 않으면 Compose는 “변화 없음”으로 판단하여 재조합을 생략하거나 draw 단계를 건너뛴다.

Box의 내부 동작

Box는 단순한 layout container로, 다음과 같은 특징이 있다.

  • 배경색, border, 클릭 등을 모두 개발자가 수동으로 제어해야 한다.
  • 상태가 변경되면 Compose는 모든 Modifier를 다시 적용하고 draw 단계도 무조건 실행한다.

실제 발생한 현상

Surface(
  color = if (isSelected) X else Y,
  border = ...
)

이 경우, color, border, shape, tonalElevation 등이 종합적으로 처리된다. 이 중 draw layer가 동일하다고 판단되면 Compose는 화면을 다시 그리지 않는다.
따라서 로그는 나오지만 실제 화면에는 아무런 변화도 보이지 않게 된다.


실험으로 확인하는 방법

Surface(
    color = if (isSelected) Color.Red else Color.Blue, // 확실한 색상 차이
    border = BorderStroke(2.dp, Color.Magenta), // 극단적인 변화
    modifier = Modifier.clickable { onSelect() }
) {
    Text(text = "테스트", modifier = Modifier.padding(20.dp))
}

이렇게 설정했음에도 UI가 변하지 않는다면, 이는 Surface 내부의 최적화 때문이라고 볼 수 있다.


결론: Surface vs Box

항목SurfaceBox
내부 최적화많음 (색상, Elevation, Context 등)거의 없음
Draw 생략 가능성높음낮음
직접 제어추상화되어 있음명확하게 제어 가능
상태 변화 반영무시될 가능성 있음즉시 반영됨

Surface는 복잡한 머티리얼 레이어를 제공하므로, 간단한 상태 기반 UI 커스터마이징에는 BoxModifier 조합이 더 안정적이다.

특히 색상이나 border로만 상태를 표현하는 경우, Surface의 내부 최적화로 인해 오히려 recomposition 누락 문제가 발생할 수 있다.


마무리

UI 컴포넌트를 만들 때는 Surface 말고 Box를 사용하자!!!! 리컴포지션 해야한다!!!

결론: Surface는 상태 변화가 있어도 재조합을 생략하는 경우가 많기 때문에, 상태 기반 UI 컴포넌트에는 적합하지 않다.

profile
안드로이드... 좋아하세요?

0개의 댓글