Simple&Natural
ViewPager2 사용 시 ViewModel이 onCleared 된 후 다시 초기화되지 않는 이슈 관련 회고 본문
ViewPager2 사용 시 ViewModel이 onCleared 된 후 다시 초기화되지 않는 이슈 관련 회고
Essense 2022. 12. 22. 14:48
일반적인 MVVM 패턴에서 ViewModel을 편리하게 사용할 수 있도록
Android는 자체적으로 ViewModel 관련 컴포넌트들을 제공하고 있다.
이때, ViewModel은 생명주기를 가지는데 이는 처음 생성할 때 지정했던 ViewModelStoreOwner에 따라 달라진다.
다음 코드를 보자.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(
this,
MyCommunityListViewModel.Factory(
requireAppContainer().communityRepository,
requireAppContainer().settingInfo
)
).get(MyCommunityListViewModel::class.java)
}
특정 Fragment에서 ViewModel을 생성하는 부분이다.
이때 owner를 해당 Fragment 로 지정했으므로 이 ViewModel의 생성과 파괴는 해당 Fragment에 의존한다.
Activity → Fragment → ViewPager → Fragments
구조로 되어 있는 경우
ViewPager 하위의 Fragment에서 위 코드를 사용하면 ViewPager를 스크롤함에 따라
Fragment 와 ViewModel의 생성과 파괴가 반복된다.
만약 해당 코드를 다음과 같이 변경하면 어떨까?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(
requireParentFragment().viewModelStore,
MyCommunityListViewModel.Factory(
requireAppContainer().communityRepository,
requireAppContainer().settingInfo
)
).get(MyCommunityListViewModel::class.java)
}
굵게 표시된 부분을 보면
this 에서 requireParentFragment().viewModelStore 로 바뀌었다.
이는 ViewPager를 가지고 있는 상위 Fragment로 ViewModel의 생성과 파괴 주기가 지정된 것을 뜻한다.
즉, 스크롤에 상관없이 ViewPager가 유지되는 한 ViewModel의 데이터는 지속적으로 남아있음을 의미한다.
만약 스크롤에 관계없이 탭 내의 데이터를 지속해서 유지하고 싶은 경우 위처럼 owner를 지정하면 되지만
이 경우엔 view가 파괴되었음에도 해당 view의 viewModel이 지속적으로 남아있는 것이 부자연스럽다.
따라서 상위 fragment의 viewModel을 생성하고 그곳에서 data를 저장하는 것이 바람직할 것이다.
private val viewModel: MyCommunityListViewModel by viewModels{
MyCommunityListViewModel.Factory(
requireAppContainer().communityRepository,
requireAppContainer().settingInfo
)
}
한 가지 더 유념해야 할 부분은
위처럼 property delegate을 이용해 ViewModel을 생성한 경우 owner는 해당 fragment로 지정되나
Fragment는 생성-파괴되지만 ViewModel은 첫 번째 onCleared 이후 다시 생성-초기화되지 않는 현상이 발생한다.
이에 대한 자세한 분석은 추가로 필요하지만, Fragment의 onDestroy 호출 시 ViewModelStoreOwner 내부에서
ViewModel 관련 cache가 그대로 남아있는 듯 보인다.
이를 방지하기 위해 property delegate 대신 맨 위의 방식처럼 Fragment의 onCreate에 viewModel을 다시 생성하는 코드를 삽입해주어 해결하였다.
'안드로이드(Android) > 이슈 및 해결' 카테고리의 다른 글
Room 마이그레이션 이슈 (0) | 2023.08.15 |
---|---|
Support 의존성을 사용하는 외부 라이브러리의 호환성 조정 방법 (0) | 2022.06.03 |
Okhttp Interceptor에서 Exception을 catch하지 못하는 이슈 (0) | 2022.05.22 |
Kotlin-kapt & ButterKnife 동시 사용 시 null 오류 (0) | 2021.04.29 |
2021-01-04 이슈 (Android Studio Build 관련 문제 해결) (0) | 2021.01.04 |