SingleLiveEvent
: 화면 회전 등 구성요소 변경 시, 이벤트가 여러번 호출되는 걸 방지하기 위해 사용 -> 단일 이벤트 사용
import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean
class SingleLiveEvent<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}
// Observe the internal MutableLiveData
super.observe(owner, Observer { t ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
})
}
@MainThread
override fun setValue(t: T?) {
pending.set(true)
super.setValue(t)
}
@MainThread
fun call() {
value = null
}
companion object {
private val TAG = "SingleLiveEvent"
}
}
소스를 간단히 살펴보자면,
pending값이 expectedValue와 동일하다면 newValue로 값을 변경 후 true를 리턴한다
setValue에서 pending이 true로 세팅 -> observe function에서 true일 때 observer.onChanged(t)가 실행됨
단점
- 하나의 observer만 제한됨
- 만약 여러개의 observer가 observe해도 그 중 하나만 호출 (어느 observer가 호출되는지 보장할 수 없음)
EventWrapper
: SingleLiveEvent의 단점을 보완하기 위해 사용, 마찬가지로 단일이벤트
/**
* 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
}
소스를 살펴보자면,
hasBeenHandled로 이벤트처리의 유무를 판단 -> false일 때, 이벤트 처리 표시 및 값 반환
위 상태에서 Event를 observe하면, 매번 observe마다
라이브데이터.observer(owner) { event ->
if(event.getContentIfNotHandled()?) // 매번 해야함
//TODO
}
event.getContentIfNotHandled()를 매번 해야한다는 불편함이 있어서
보통 EventObserver를 같이 사용합니다
[EventObserver]
import androidx.lifecycle.Observer
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.getContentIfNotHandled()?.let { value ->
onEventUnhandledContent(value)
}
}
}
EventObserver를 사용하면 훨씬 간결해집니다