Android – LiveData로 일회성 이벤트 처리하기

안드로이드 프로젝트에서 MVVM 패턴으로 아키텍처를 구성하다 보니, 데이터 바인딩을 이용하여 일회성 이벤트를 처리해야 하는 경우가 생긴다. 경고문 출력, 액티비티 이동, 혹은 프래그먼트 전환 등. 아마 그런 경우 대개 이런 형태를 취할 것이다.

데이터바인딩 – 뷰모델 – LiveData – Activity or Fragment 에서 옵저빙

그러나 문제가 있다. LiveData는 ViewModel의 데이터를 핸들링하기 위해 사용하는 동시에, 기기의 상태 변화 (디바이스 가로세로 변화, 혹은 액티비티가 메모리 부족 등의 이유로 재실행 되는 경우)에 대응하기 위해 사용한다. 때문에 일회성으로 출력돼야 하는 데이터들이 뷰가 리프레시될 때마다 의도치 않게 작업을 반복 수행 하게 된다. 이 문제를 고려해서 단순 코딩을 하면 이렇게 된다.

1. 단순하게 예외 처리

viewModel.liveData.observe(this, Observer {
     it?.let {
         // 작업 수행
         viewModel.liveData.value = null
     }
})

물론 이렇게 코딩하면 의도한 대로 일회성으로 이벤트를 처리하고, LiveData가 가지는 데이터 값을 null로 초기화해서, 다음번에는 작업이 발화되지 않도록 할 수 있다. 그러나 데이터가 null 인 것인지, 작업이 이미 발화되어 null이 된 것인지 구별하기가 힘들다.

꽤 괜찮아 보이는 방법을 발견했고 아래 방법은 해당 웹페이지에서 발췌한 방법이다. LiveData with SnackBar, Navigation and other events

2. Event wrapper 이용하기

Event 클래스는 각 값을 가지면서, 해당 콘텐츠가 사용되었는지 여부를 기억하게 하여, 중복 사용을 막을 수 있도록 한다. 첫 번째 방법으로 제시한 단순하게 예외 처리한 것과 다른 점은, 실행 여부를 저장해서 중복 사용을 막기 때문에 이후에도 데이터 값이 필요한 경우 사용 가능하다. 또한 데이터의 출처가 명확하기 때문에 훨씬 안전하다고 생각된다.

사용은 단순히 이렇게 하면 된다.

val messageLiveData = MutableLiveData<Event<String>>()
mssageLiveData.value = "something"
viewModel.messageLiveData.observe(this, Observer {
     it.getContentIfNotHandled()?.let{
         Toast.makeText(requireContext(), it, Toast.LENGTH_SHORT).show()
     }
 })

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다