MVVM 패턴을 기반으로 프로젝트를 진행하던 중, 아래와 같은 오류가 발생하였습니다.
JNI DETECTED ERROR IN APPLICATION: JNI FindClass called with pending exception java.lang.IllegalStateException: Can't access ViewModels from detached fragment
Detached된 Fragment에서 ViewModel에 접근할 수 없다는 내용인데요...
무슨 뜻인지 해석했음에도 불구하고 몇 시간의 삽질을 해야만 했습니다..ㅎㅎ
곰곰이 생각해보니 Android Lifecycle을 조금만 생각해봤다면 금방 해결했을텐데 말이죠.. 😅
어떤 코드에서 오류가 발생하였는지 함께 살펴보겠습니다. 🎈
class MyFragment() : SuperBottomSheetFragment() {
lateinit var binding: ActivityReviewBinding // 바인딩 객체
val viewModel: ReviewViewModel by viewModel() // 사용할 뷰모델
constructor(model: Lot) : this() {
viewModel.model = model // ViewModel의 모델 데이터 초기화
binding.lifecycleOwner = this // 라이프사이클 설정
binding.model = viewModel.model // 데이터바인딩 모델 세팅
}
위 코드는 Fragment 코드 중 일부입니다.
맨 상단에 Koin 라이브러리를 사용하여 ViewModel을 주입받고,
constructor에서 라이프사이클과 전달받은 데이터를 초기화해줍니다.
하지만, 여기서는 한 가지 문제가 존재합니다.
constructor는 Fragment가 Attach되기 이전에 실행된다는 점입니다.
오류 문구를 보면 알 수 있다싶이, Detached된 상태에서는 ViewModel에 접근할 수 없습니다.
바로 ViewModel은 LifeCycle을 고려하기 때문이죠.
그럼 어떻게 해결할 수 있을까요?? 🤨
방법은 간단합니다.
class MyFragment(var model: Lot ?= null) : SuperBottomSheetFragment() {
lateinit var binding: ActivityReviewBinding
val viewModel: ReviewViewModel by viewModel()
override fun onAttach(context: Context) {
super.onAttach(context)
viewModel.model = model
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
binding = DataBindingUtil.inflate(
LayoutInflater.from(requireContext()),
R.layout.activity_review,
container,
false
)
binding.lifecycleOwner = this
binding.model = viewModel.model // 데이터바인딩 모델 세팅
model = null // 해당 Model은 ViewModel에 전달하였으므로 null로 초기화하여 메모리를 아껴준다.
initView()
return binding.root
}
constructor로 생성자를 별도로 사용하지 않고 ViewModel에 초기화시킬 데이터를 가져옵니다.
(위 상황은 필자의 경우이므로, 본인 상황에 맞춰서 코드를 작성하시면 됩니다.)
그리고 Fragment가 Activity에 연결되는 경우 호출되는 onAttach() 메서드를 재정의해주어야 합니다.
바로 이 때, ViewModel에 접근하여 수행해야 하는 로직을 처리해주면 됩니다.
그리고 binding은 onCreateView() 메서드쪽으로 모두 옮겨주었죠!
수정 결과

해당 코드처럼 수정 후 프로젝트를 실행하니 오류가 해결된 모습을 확인할 수 있었습니다!
본인은 DialogFragment를 사용하였기 때문에 하단에서 Fragment가 튀어나왔습니다.
내용에 오류가 있거나, 질문이 있으신 분들은 댓글을 남겨주시면 감사하겠습니다! 😊
'Android > 스터디' 카테고리의 다른 글
[Android] 안드로이드 Strings.xml 국가별 언어 설정 방법 및 국가 코드 정리 (5) | 2021.12.28 |
---|---|
[Android] RecyclerView LayoutPosition vs AdapterPosition 차이를 알아보자! (0) | 2021.12.22 |
[Android] 카카오맵을 2개 이상 ADD했을 때 발생하는 오류 대처 방법! DaumMap does not support that two or more (2) | 2021.12.17 |
[Android] OutOfMemoryError: Java heap space 오류 해결 방법 (0) | 2021.12.07 |
[Android] 코루틴 suspendCancellableCoroutine 비동기 처리 (0) | 2021.12.02 |