MVVM UI 이벤트 처리 어떻게 해야해?

1 minute read

1. 개요

MVVM 패턴을 이용하면 UI관련 처리 이벤트가 발생한 경우 한번의 옵져빙을 하고 관찰자가 비활성화 되어야 합니다. 이러한 경우에 LiveData를 대체할 수 있는 방법을 소개해드리겠습니다.

2. 코드

/**
 * Used as a wrapper for data that is exposed via a LiveData that represents an event.
 */
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
}

/**
 * An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has
 * already been handled.
 *
 * [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled.
 */
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let { value ->
            onEventUnhandledContent(value)
        }
    }
}

3. 사용예시

class MainViewModel: ViewModel() {

    private val _clickToNext = MutableLiveData<Event<Unit>>()
    val clickToStart : LiveData<Event<Unit>>
        get() = _clickToNext
    fun startNext(){
        _clickToNext.value = Event(Unit)
    }

}
mainViewModel.clickToNext.observer(this, EventObserver {
    startActivity(Next...)
})

이러한 형태로 사용을 하게 되면, 한번 만 사용하는 것을 확실히 알 수 있습니다.

4. 참고자료

5. 결론

평소 SingleLiveEvent를 사용하였지만, UnitTest를 작성하는 과정에서 어려움을 느껴 자료를 찾아보던 중 알게 되었습니다. 이벤트 처리 과정에서 명확히 할 수 있는 좋은 자료입니다.

Updated:

Leave a comment