Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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

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

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

Event

Code Block
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
}

사용 예제

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

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


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

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

SingleLiveEvent

Code Block
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
    }
}

사용 예제

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

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

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