LiveData 사용시 발생했던 이슈에 대해서 정리했습니다.
LoginViewModel.kt
ChoiceAddressFrag.kt(지역선택 프레그먼트)
위의 코드를 보시면 지역선택 프래그먼트에서 ViewModel의 LiveData를 구독 후 관찰하는 값의 변경이 생기면 옵저버가 콜백메서드를 실행시켜서 로그인 화면으로 이동하는 코드를 작성했습니다.
위의 Gif파일을 보시면 처음에는 지역선택 프래그먼트에서 가입완료 버튼을 누르면 로그인화면으로 이동하지만
그 이후에는 이메일인증 프래그먼트에서 다음 버튼을 눌렀을 때 바로 로그인화면으로 이동하는 것을 확인할 수
있습니다.
원인
ChoiceAddressFrag.kt(지역선택 프레그먼트)
원인은 이메일인증 프래그먼트에서 지역선택 프래그먼트로 이동하자마자 이전에 구독했던 ViewModel의 LiveData에서 옵저버가 이벤트를 발생시켜 등록된 콜백 메서드가 실행되어 로그인 화면으로 이동했기 때문입니다.
그러면 왜 LiveData에서 관찰하는 값이 바뀐것이 아닌데 이벤트가 실행되었는지 확인해봅시다.
ViewModel의 라이프사이클
ViewModel LifeCycle의 특징
-위의 그림처럼 AAC의 ViewModel은 Activity의 UI와 관련된 데이터를 보관하기 위해 설계되었습니다.
그러므로 Activity가 화면회전에 의해 onDestory되어도 ViewModel에 있는 데이터는 소멸하지 않습니다.
-ViewModel에 있는 LiveData는 위와 같은 ViewModel의 LifeCycle에 의해 소멸되지 않고 InActive(비활성화) 상태가
됩니다
LiveData의 InActive(비활성화) -> Active(활성화)
-일반적으로 LiveData는 관찰하는 값이 변경되었을 때에만 이벤트를 발생시켜 등록된 콜백메서드를 실행시키지만
예외적으로 LiveData가 InActive -> Active 상태로 변경될 때도 콜백 메서드를 실행시킵니다.
-그러므로 다시 지역선택 프래그먼트로 이동 시 비활성화 되었던 LiveData가 Active상태로 변경되면서
예외적으로 콜백메서드를 실행시키게 된 것 입니다.
EventWrapper를 사용한 해결방법
Event.kt
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
LoginViewModel.kt
//쓰기, 읽기, 수정 가능
private val _LiveRegister = MutableLiveData<Event<User>>()
//읽기만 가능
val liveRegister: LiveData<Event<User>>
get() = _LiveRegister
fun requestRegisterUser(user: User) {
//최종적인 API 통신 응답값을 LiveData에 입력
//-Invoke fun 사용
registerUseCase(user, viewModelScope) {
_LiveRegister.postValue(Event(it))
}
}
ChoiceAddressFrag.kt(지역선택 프레그먼트)
private fun subscribeToLiveData() {
//로그인 화면으로 이동
viewModel.liveRegister.observe(viewLifecycleOwner) { event ->
event.getContentIfNotHandled()?.let {
val action =
ChoiceAddressFragDirections.actionChoiceAddressToLogin()
findNavController().navigate(action)
}
}
-위의 코드처럼 Event클래스를 하나 만들어서 LiveData에 Event클래스를 한번 더 넣은 후에
-프래그먼트에서 Event를 받을 때는 event.getContentIfNotHandled()메서드를 사용해서 콜백메서드를 실행시키면 된다.
참고자료
https://seosh817.tistory.com/9
[Android] 안드로이드 SignleLiveEvent 와 Event Wrapper 클래스 (AAC ViewModel, LiveData 이슈)
지인에게 왜 화면 회전을 시키면 한번 띄워졌던 토스트메시지 혹은 Dialog가 왜 다시 띄워지는지 모르겠다는 질문을 받았습니다. 그 지인의 ViewModel 부분 코드입니다. 액티비티에서는 아래의 라이
seosh817.tistory.com
https://woochan-dev.tistory.com/86
Event용 LiveData 적용하기
MVVM 아키텍에서 LiveData를 쓰다보면 흔하게 마주할 수 있는 상황이 바로 Event 일회성 처리에 대한 문제이다. private val _eventStartSettingActivity = MutableLiveData () val eventStartSettingActivity: L..
woochan-dev.tistory.com
https://jaeryo2357.tistory.com/94
[Android] LiveData의 Data를 한번만 관찰
안녕하세요. 점냥입니다:) 이번 포스팅 주제로는 SingleLiveData 입니다. Android AAC LiveData의 사용법 중 하나로 LiveData를 아직 잘 모르신다면 링크를 먼저 읽어와 주세요! LiveData의 변경된 Data를 오직 한
jaeryo2357.tistory.com
(깊이 있게 잘 설명되어 있음)
MVVM의 ViewModel에서 이벤트를 처리하는 방법 6가지
지금 개발하시는 코드에서 ViewModel의 이벤트 처리를 어떻게 하고 계신가요? 헤이딜러에서 LiveData -> SingleLiveData -> SharedFlow -> EventFlow로 이벤트 처리 방법을 변화 하기까지 과정을 소개합니다…
medium.com
'개발 시행착오 정리' 카테고리의 다른 글
[안드로이드] 리사이클러뷰 안에 리사이클러뷰 사용시 안에 있는 리사이클러뷰가 터치가 안될 때 (0) | 2023.01.05 |
---|---|
운동친구 구하는 어플 기획에서 이상한 부분 (0) | 2022.02.14 |
[안드로이드] Java서버 실시간 단체 채팅 구현 과정 및 시행착오 정리 (0) | 2022.02.10 |
[안드로이드] 코틀린 WebRTC 화상 통화 구현 진행 과정 및 시행착오 정리 (0) | 2022.02.08 |
[안드로이드] 이미지 여러 장 처리 시행착오 및 구현 과정 (1) | 2022.01.27 |
댓글