SingleLiveEvent

h_hi·2021년 4월 4일
0

AAC

목록 보기
7/8

SingleLiveEvent

ViewModel 에서 View 에 이벤트를 전달할 때, 값을 전달하는 경우가 아닌 이벤트가 발생했다는 사실만을 전달하고 싶을 때, 아래의 코드와 같이 Unit 값을 전달하여 이벤트를 감지하도록 했었습니다.

    private val _signUpClickEvent = MutableLiveData<Unit>()
    _signUpClickEvent.value = Unit

위의 코드는 비효율적일 뿐만 아니라, LiveData를 이용하기에 View의 재활성화 (start나 resume 상태로 재진입)가 될 경우에도 LiveData가 observe를 호출하여, 불필요한 이벤트까지 일어나는 경우가 있습니다.
이를 방지하기 위해 SingleLiveEvent 를 사용합니다.

구글 샘플 코드

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


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


    // Observe the internal MutableLiveData
    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, Observer {
            if (isPending.compareAndSet(true, false)) {
                observer.onChanged(it)
            }
        })
    }

    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    fun call() {
        value = null
    }
}

SingleLiveEvent라는 MutableLiveData를 상속한 클래스를 만듭니다.
isPending.compareAndSet(true, false)라는 것은, 위의 pending 변수가 true면 if문 내의 로직을 처리하고 false로 바꾼다는 것입니다. setValue를 통해서만 pending값이 true로 바뀌기 때문에, Configuration Changed가 일어나도 pending값은 false이기 때문에 observe가 데이터를 전달하지 않습니다.데이터의 속성을 지정해주지 않아도 call만으로 setValue를 호출 가능합니다.

사용법

class ListViewModel : ViewModel {
    private val _navigateToDetails = SingleLiveEvent<Any>()

    val navigateToDetails : LiveData<Any>
        get() = _navigateToDetails


    fun userClicksOnButton() {
        _navigateToDetails.call()
    }
}

Reference

[medium]LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)
[찰스의 안드로이드]SingleLiveEvent로 이벤트 처리하기
[치킨과 개발의 상관관계] [Android] SingleLiveEvent의 원리

profile
안드로이드, flutter 개발자

0개의 댓글