ViewModel 초기화 하는 방법
우리는 데이터 보존을 위해 ViewModel 를 초기화하여 View(Fragmet, Activity) 에서 사용한다.
ViewModel 를 초기화 하는 방법은 대표적으로 두 가지로 나눌 수 있다.
1. ViewModelProvider.
private val viewModel: MyViewModel by lazy {
ViewModelProvider(getViewModelOwner())[MyViewModel::class.java]
}
2. by viewModels
private val viewModel by viewModels<MyViewModel>()
겪은 이슈
as-is > to-be 로 코드 리팩토링할 때 as-is 에서 작업했던 ViewModel 초기화 방식과 to-be 방식이 위 두 가지로 나뉘었다.
as-is 에서는 ViewModelProvider 를 이용하여 초기화 하였고, to-be 에서는 by viewModels 를 이용하여 지연 초기화를 했다.
코드를 옮기면서, viewModel 방식을 to-be (by viewModels) 방식으로 초기화를 하였는데
as-is 에서 정상적으로 동작했던 Livedata Observing 이 되지 않았다.
아니 왜 안돼 !!
as-is 에서 정상적으로 되는게 왜?
초기화 방식만 다를 뿐이지 제대로 한 거 아니야?
문제점
나는 여기서 ViewModel Lifecycle 를 놓치고 있었다.
ViewModel scope 는 View 와 생명주기가 동일하다는 걸 알고 있지만, 텍스트 그대로 인지'만' 한 거 같다..
이렇게 Observing 이 되지 않은 이유가 Lifecycle 문제라는 걸 인식하지 못했다.
[상황]
A Fragment 에 B Fragment 와 C Fragment 를 띄우고
A,B,C Fragment 에 모두 동일한 ViewModel 을 초기화하여 사용했다.
B Fragment 에서 Livedata 값을 변하게 하여, A Fragment 에서 Observing 을 하게끔 코드를 짰다.
그런데, A Fragment 에서 해당 Observing 이 되지 않은 문제가 발생했다.
해결 방법
위에서 겪은 문제점의 원인은 A Fragment 에서 by viewModels 로 지연 초기화한 ViewModel 은 A ViewModel 이고,
B Fragment 에서 초기화한 by viewModels 로 지연 초기화한 ViewModel 은 B ViewModel 로 인식해야 한다.
즉, A ViewModel 은 A Fragment 의 생명주기를 따를 수 밖에 없다.
같은 ViewModel::class 라고 하더라도
A ViewModel 에서 값이 변경돼도 B Fragment 에서 Observing 한게 동작하지 않을 수 있다.
이 방법을 해결하기 위해 두 가지 방법이 존재한다.
[해결 방안]
A Fragment와 B Fragment 는 동일한 ViewModel 을 사용해야 한다.
1. ViewModel 생명주기를 Activity 기준으로 맞춰 Activity 위에 띄운 Fragment 들이 하나의 ViewModel 을 공유할 수 있도록 한다.
> 위에서 작성한 ViewModel 초기화 방법1 을 이용.
2. A Fragment 와 B Fragment 에서 발생하는 이벤트들을 한 곳에 받는 Adapter 를 만들고, Adapter 에서 ViewModel 의 데이터를 변환시키는 방식으로 처리한다.
참고
(ref. https://developer.android.com/topic/libraries/architecture/viewmodel?hl=ko)