Page tree
Skip to end of metadata
Go to start of metadata

LiveData를 통한 이벤트 처리의 문제

화면 회전과 같은 Configuration change가 발생하면 Activity는 onDestroy() 이벤트가 발생하고 다시 onCreate() 이벤트가 발생하면서 재생성됩니다.

하지만 ViewModel은 onCleared() 이벤트가 발생하지 않고 UI를 위해 데이터를 그대로 보존하고 있습니다.

따라서 Configuration change 이전에 LiveData를 통해 이벤트를 전달했었다면 Activity는 다시 생성되면서 onCreate()에서 LiveData를 구독하면서 이벤트가 다시 전달됩니다.

Event

class Event<out T>(private val content: T) {
    var consumed = false
        private set

    fun consume(): T? {
        return if (consumed) {
            null
        } else {
            consumed = true
            content
        }
    }

    fun peek(): T = content
}

사용 예제

class MainViewModel: ViewModel() {
    private val _onEvent = MutableLiveData<Event<Any>>()
    val onEvent: LiveData<Event<Any>>
        get() = _onEvent

    fun doSomething() {
        _onEvent = Event(Unit)
    }
}


viewModel.onEvent.observe(lifecycleOwner) {
    it.consume()?.let {
        // 이벤트 처리
    }
}

  • 명시적으로 함수를 사용함으로써 의도를 밝힐 수 있다.
  • consume()을 통해서 값을 1번만 가져올 수 있다.
  • peek()를 통해 사용여부와 상관없이 값을 가져올 수 있다.
    • 주로 테스트 코드에서 사용된다.

SingleLiveEvent

class SingleLiveEvent<T> : MutableLiveData<T>() {
    private val pending = AtomicBoolean(false)

    override fun observe(owner: LifecycleOwner, observer: Observer<in T?>) {
        super.observe(owner, { value ->
            if (pending.compareAndSet(true, false)) {
                observer.onChanged(value)
            }
        })
    }

    @MainThread
    override fun setValue(value: T?) {
        pending.set(true)
        super.setValue(value)
    }

    @MainThread
    fun call() {
        value = null
    }
}

사용 예제

class MainViewModel: ViewModel() {
    private val _onEvent = MutableLiveData<Any>()
    val onEvent: LiveData<Any>
        get() = _onEvent

    fun doSomething() {
        _onEvent.call()
    }
}
viewModel.onEvent.observe(lifecycleOwner) {
    // 이벤트 처리
}

  • MutableLiveData를 쓰듯이 사용할 수 있다.
  • 여러 개의 옵저버에 이벤트를 전달할 수 없도록 설계되었기에 만약 여러개의 옵저버가 등록되어 있다면 어떤 것이 실행 될지는 보장되지 않는다.
  • No labels