-
ComposeView가 언제 죽는지 아세요? — ViewCompositionStrategy 파헤치기Android📱 2026. 7. 10. 20:38
ComposeView가 언제 죽는지 아세요? — ViewCompositionStrategy 파헤치기
기존 View 기반 앱에 Compose를 조금씩 얹다 보면 반드시
ComposeView를 만나게 됩니다. XML 레이아웃 한복판에ComposeView를 하나 놓고setContent { }안에서 Composable을 그리는 거죠.<androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view" android:layout_width="match_parent" android:layout_height="wrap_content" />대부분은 잘 됩니다. 그런데 Fragment에서 쓰다 보면 어느 순간 이상한 크래시나 상태 꼬임을 만나게 되는데, 그 범인이 바로 오늘의 주인공
ViewCompositionStrategy입니다.
컴포지션에도 "생명주기"가 있다
Compose를 쓰면 화면 뒤에 Composition(컴포지션)이라는 게 생깁니다.
setContent로 만든 UI 트리의 상태를 들고 있는 실체죠. 이 컴포지션은 언젠가는 정리(dispose) 되어야 합니다. 안 그러면 메모리 누수가 나니까요.그럼 "언제" 정리해야 할까요? 이걸 결정하는 정책이 바로
ViewCompositionStrategy입니다.한 줄 요약:
ViewCompositionStrategy= ComposeView의 컴포지션을 언제 dispose 할지 정하는 규칙
기본값은 뭘까?
ComposeView는 아무것도 설정 안 하면ViewCompositionStrategy.Default를 씁니다. 이게 현재 가리키는 실제 전략은:DisposeOnDetachedFromWindowOrReleasedFromPool공식 문서 표현을 그대로 옮기면:
"The default disposes the Composition when the underlying
ComposeViewdetaches from the window, unless it is part of a pooling container such as aRecyclerView."즉, 뷰가 윈도우에서 detach 될 때 컴포지션을 정리합니다. 단, RecyclerView 같은 pooling 컨테이너 안에 있으면 pool에서 재활용/폐기될 때 정리하고요.
일반적인 Activity + 단순 View 계층에서는 이 기본값으로 충분합니다.
문제는 Fragment에서 터진다
Fragment의 함정은 유명하죠. Fragment 자체의 생명주기와 Fragment의 View 생명주기가 다릅니다.
- Fragment가 백스택으로 들어가면 → View는 destroy 되지만 Fragment 인스턴스는 살아있음
- 다시 돌아오면 →
onCreateView가 다시 호출되어 View가 새로 만들어짐
그런데 기본 전략은 "윈도우에서 detach 될 때" 정리합니다. Fragment가 백스택에 들어갈 때 뷰가 detach는 되지만, 이 타이밍이 Fragment의 view lifecycle과 딱 맞아떨어지지 않아서 컴포지션이 원치 않는 시점까지 살아있거나, 상태가 꼬이는 문제가 생깁니다.
그래서 Fragment 안의
ComposeView에는 명시적으로 다른 전략을 지정하는 게 정석입니다.class ExampleFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { val view = inflater.inflate(R.layout.fragment_example, container, false) val composeView = view.findViewById<ComposeView>(R.id.compose_view) composeView.apply { // ✅ 뷰의 LifecycleOwner가 destroy될 때 컴포지션 정리 setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed ) setContent { MaterialTheme { Text("Hello Compose!") } } } return view } }DisposeOnViewTreeLifecycleDestroyed는 뷰 트리에서 가장 가까운 LifecycleOwner(Fragment의 viewLifecycleOwner)를 자동으로 찾아, 그 생명주기가 destroy될 때 컴포지션을 정리합니다. Fragment의 view lifecycle과 정확히 일치하죠.
4가지 전략 총정리
전략 언제 dispose 되나 언제 쓰나 DisposeOnDetachedFromWindowOrReleasedFromPool⭐기본값윈도우에서 detach될 때 (pool이면 폐기될 때) 대부분의 일반적인 경우, RecyclerView DisposeOnViewTreeLifecycleDestroyed뷰 트리의 LifecycleOwner가 destroy될 때 Fragment 안에서 쓸 때 DisposeOnLifecycleDestroyed(lifecycle)직접 넘긴 Lifecycle이 destroy될 때 특정 Lifecycle에 명시적으로 묶고 싶을 때 DisposeOnDetachedFromWindow⚠️deprecated윈도우에서 detach될 때 (pooling 미고려) 사용 지양 (기본값으로 대체됨)
RecyclerView는 어떻게?
의외로 아무것도 안 해도 됩니다. 기본값인
DisposeOnDetachedFromWindowOrReleasedFromPool이 이미 pooling 상황을 고려해서 설계됐거든요. RecyclerView가 item view를 재활용할 때 컴포지션을 알아서 정리해줍니다.굳이
DisposeOnViewTreeLifecycleDestroyed같은 걸 RecyclerView item에 넣으면 오히려 재활용 최적화를 방해하니 주의하세요.
결론
- Compose를 View에 얹으면 컴포지션 정리 타이밍을 신경 써야 한다.
- 기본값 =
DisposeOnDetachedFromWindowOrReleasedFromPool→ 일반 View / RecyclerView는 그대로 OK. - Fragment 안에서는 반드시
DisposeOnViewTreeLifecycleDestroyed로 바꿔라. (view lifecycle 불일치 문제 예방) DisposeOnDetachedFromWindow는 deprecated, 쓰지 말 것.
"내 ComposeView는 언제 죽는가?" — 이 질문에 한 번쯤 답해보면, interop 단계에서 만나는 미묘한 버그의 절반은 예방됩니다.
참고 자료
'Android📱' 카테고리의 다른 글
a2ui: AI 에이전트가 처음 보는 Android UI를 그리는 법 (1) 2026.08.03 Jetpack Compose Side Effects 파헤치기 — RememberObserver로 이해하는 effect 핸들러 (1) 2026.08.01 Navigation 3 설명회 (0) 2026.07.06 [Android] pendingIntent putExtra 및 주의 사항 (0) 2024.09.12 [Android] Sensor를 이용하여 방위각 구해보기~~ (1) 2024.06.04