반응형
SingleLiveEvent란?
LiveData를 사용하던 도중 화면에 진입했을 때 observe가 되면서 재호출이 되는 경우가 있다.
예) 휴대폰 설정 후 화면 진입시 LifeCycle에 의해 다시 호출 등
View의 재활성화 (start나 resume 상태로 재진입)가 되면서 LiveData가 observe를 호출하여,
불필요한 Observer Event까지 일어나는 경우가 있습니다.
이를 방지하기 위해 기존 LiveData를 상속하여 만들어낸 것이 SingleLiveEvent입니다.
여러가지 소스 방법이 있는것 같다. (파일명만 다름. 원리는 다 같을겁니다)
SingleLiveEvent
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"
}
}
SingleEvent
open class SingleEvent<T>(value: T) {
var value = value
private set
private var isAlreadyHandled = false
fun isActive(): Boolean = if (isAlreadyHandled) {
false
} else {
isAlreadyHandled = true
true
}
}
fun <T> LiveData<SingleEvent<T>>.observeEvent(owner: LifecycleOwner, observer: Observer<T>) =
observe(owner) {
if (it.isActive()) {
observer.onChanged(it.value)
}
}
fun MutableLiveData<SingleEvent<Unit>>.emit() = postValue(SingleEvent(Unit))
fun <T> MutableLiveData<SingleEvent<T>>.emit(value: T) = postValue(SingleEvent(value))
Event
open class Event<out T>(private val content: T) {
@Suppress("MemberVisibilityCanBePrivate")
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 {
onEventUnhandledContent(it)
}
}
}
사용방법 (SingleEvent활용)
ViewModel.kt
private val _deleteErrMsg = MutableLiveData<SingleEvent<Unit>>()
val deleteErrMsg: LiveData<SingleEvent<Unit>> = _deleteErrMsg
Fragment.kt
deleteErrMsg.observe(this@ExtraServiceSettingDetailFragment) {
//원하는 동작
}
이를 통해 UI 이벤트를 한 번만 처리하고자 할 때 SingleLiveEvent를 사용할 수 있습니다.
주로 MVVM 아키텍처와 함께 ViewModel에서 LiveData를 사용하여 UI와 데이터 간의 통신을 단순화하는 데 활용됩니다.
참조 : https://zladnrms.tistory.com/146
반응형
'안드로이드' 카테고리의 다른 글
푸시 알림 처리를 위한 PendingIntent 및 onNewIntent 사용하기 (0) | 2024.03.14 |
---|---|
startActivityForResult 및 ActivityResultLauncher에 대한 명확한 이해 (0) | 2024.03.14 |
안드로이드 layout xml @+id와 @id의 의미 (0) | 2024.02.07 |
Firebase FCM 기존 HTTP에서 HTTP v1로 마이그레이션 (0) | 2024.01.29 |
테스트 코드 작성 junit assertEquals (0) | 2023.10.13 |