본문 바로가기
Mobile App/Android

[안드로이드] by viewModels, LiveData Observing 이 안되는 이유

by Jman 2024. 2. 4.

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)