findViewTreeLifecycleOwner == null 인 경우?
이따금식 LifecycleOnwer 를 사용하기 위해, View 의 확장함수인 findViewTreeLifecycleOwner 를 사용하는 경우가 있습니다.
간혹 아무 생각 없이 사용하다보면 findViewTreeLifecycleOwner 가 null 을 반환하는 경우가 있습니다.
RecyclerView 에서 사용하는 케이스는 https://pluu.github.io/blog/android/2021/09/20/lifecycleowner/ 에서 잘 설명하고 있어서 해당 글을 참고 해도 좋을 것 같습니다.
RecyclerView 에서는 doOnAttach 함수를 사용하여, Lifecycle 을 얻어올 수 있지만, doOnAttach 로 해결되지 않는 케이스들도 존재 합니다.
먼저 ViewTreeLifecycleOwner.get(this) 함수의 구현체를 보면
while 문을 돌면서 부모 뷰를 찾고 부모 뷰에서 R.id.view_tree_lifecycle_owner 로 저장된 Tag 가 있는지 확인하여 해당 뷰에 set 되어 있는 LifecycleOwner 를 사용하게 되는 원리 입니다.
결국 타고 타고 올라가다 보면, 대부분 상황은 (Component)Activity, Fragment, DialogFragment 와 마주할 것이고, 각 클래스들은 LifecycleOwner 의 구현체(implement)를 가지고 있고 생성될 때 LifecycleOwner set 되고 있습니다.
그럼 어떤 상황이면 findViewTreeLifecycleOwner 가 null 을 반환될 수 있을지 생각해보면, 타고 타고 올라갔을 때, Activity, DialogFragment, Fragment 같이 Lifecycle 의 구현체를 가지고 있지 않고, set 해주지 않는 곳이면 모두 발생하게 됩니다.
가령 대표적인 경우가 Dialog, PopupWindow 등의 경우 입니다.
Lifecycle 의 구현체를 가지지 않기 때문에 항상 null 일수 밖에 없습니다.
따라서
ViewTreeLifecycleOwner.set(decorView /* 부모 뷰 */, lifecycle or viewLifecycle)
위와 같이 Dialog, PopupWindow 컨텐츠 영역 중 부모 뷰에 사용하고 싶은 Activity 의 lifecycle 이나 Fragment 의 lifecycle 혹은 viewLifecycle 등을 넣어주게 되면, 위에서 이야기한 것 처럼 while 문을 통해 부모에 있는 lifecycle 를 가져와서 사용할 수 있게 됩니다.
간단한 내용을 괜시리 길게 쓴 것 같은 느낌이네요.
중요한 점은, 뷰가 window 에 붙어 있는 상황과 상관 없이 부모중에 lifecycle 구현체를 가지고 있지 언제든 findViewTreeLifecycleOwner 가 null 이 될 수 있다는 점입니다.
Compose 에서는
CompositionLocalProvider(
LocalLifecycleOwner provides this,
)
val LocalLifecycleOwner = staticCompositionLocalOf<LifecycleOwner> {
noLocalProvidedFor("LocalLifecycleOwner")
}
와 같은 방식을 사용하여 좀더 쉽게 처리할 수 있습니다.
그럼 20000