2021. 7. 17. 21:51ㆍAndroid
TL;DR:
Fragment 에서 아래와 같이 viewModel 생성했을 때, onAttach() 메서드가 호출된 이후에 viewModel 에 접근해야 한다.
private val viewModel by viewModels<YourViewModel>()
올바른 접근 (⭕️)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.apply {
viewModel.initAddTask(getInt(ARG_TASK_ID).toLong())
}
}
올바르지 않은 접근 (❌)
override fun onAttach(context: Context) {
super.onAttach(context)
arguments?.apply {
viewModel.initAddTask(getInt(ARG_TASK_ID).toLong())
}
}
🚧 바로 위의 예제와 같이, onAttach() 내에서 viewModel 에 접근하면, 아래와 같은 오류를 마주칠 것이다.
java.lang.IllegalStateException: You can consumeRestoredStateForKey only after super.onCreate of corresponding component
오류가 발생하는 이유
Fragment.viewModels() 의 내부 구현체를 보자.
주석을 살펴보면,
This property can be accessed only after this Fragment is attached i.e., after* [Fragment.onAttach()]
이 프로퍼티(viewModel) 은 fragment 가 attached 된 이후에 접근 가능하다 라고 쓰여있다.
어떻게 보면 당연하다고 생각되는 것이, viewModels() 로 생성 시 viewModel 의 default scope(기본 범위)가 해당 fragment 이기 때문에.
*
* This property can be accessed only after this Fragment is attached i.e., after
* [Fragment.onAttach()], and access prior to that will result in IllegalArgumentException.
*/
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
단, activityViewModels() 로 생성 후 접근하면 오류가 발생하지 않는다.
Fragment 에서 아래와 같이 activityViewModels 로 생성하면 onAttach() 에서 viewModel 에 접근해도 위와 같은 오류는 발생하지 않았다.
private val viewModel by activityViewModels<YourViewModel>()
실제로 activityViewModels 의 내부 구현체를 보면, viewModels 와 동일하게 onAttach() 후에 접근해야 한다고 쓰여 있으나,
* This property can be accessed only after this Fragment is attached i.e., after
* [Fragment.onAttach()], and access prior to that will result in IllegalArgumentException.
*/
@MainThread
inline fun <reified VM : ViewModel> Fragment.activityViewModels(
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
실제로 테스트했을 때 정상적으로 동작한 이유는,
activityViewModels 로 viewModel 을 생성한다는 것은 fragment 의 parent activity scope의 viewModel 을 사용하는 것으로, parent activity 는 이미 생성되어 있는 상태기 때문에 별다른 exception 없이 동작한 것으로 생각된다.
'Android' 카테고리의 다른 글
[Android] Recyclerview 클릭한 아이템을 가운데로 scroll 되게 하기 (2) | 2021.08.16 |
---|---|
[Android] Progress 를 나타내는 Custom ProgressBar 구현하기 (0) | 2021.08.08 |
[Android] 유용한 ADB 명령어 모음 (0) | 2021.07.05 |
[Android] 잃어버린 Key store password (키 스토어 비밀번호) 찾기 (1) | 2021.06.28 |
[Android] App Signing Key Certificate Fingerprint (앱 서명 인증서) 구하기 (SHA-1, SHA-256) (1) | 2021.06.19 |