최데브는 오늘도 프로그래밍을 한다.

StateFlow 원시성 보장하기 본문

Android/Coroutine

StateFlow 원시성 보장하기

최데브 2022. 9. 19. 22:31
반응형

StateFlow를 MVVM 패턴에서 UI 상태를 관리하고 반영하는데 사용하곤 했다.

flow를 반복적을 관찰하며 최신 UI 상태를 얻어서 view에 보여줄 수 있는데

class MainViewModel: ViewModel(){
    _viewState.value = _viewState.value.copy(checked = true)
 
}

위 코드처럼 copy 함수를 사용해서 다른 값을 유지하면서 하나 이상의 속성을 변경하는것도 가능하다.

 

갑자기 copy 이야기를 뜬금없이 왜 했냐?

이런식으로 값의 수정이 일어나면 copy가 완료된 시점과 stateflow에 새로운 값이 내보내지는 시간

그 사이에 우연히 다른 코루틴이 다른 속성의 값을 업데이트 했다면?

의도치 않은 data class 값이 만들어질수도 있을 것이다. 이를 우리는 원자성을 보장하지 않는다고 한다.

 

여기서 오늘 말하려고 했던 update가 나온다. 아래처럼 사용하면 위의 문제를 해결하고 원자성을

보장할 수 있게된다.

    viewModelScope.launch(Dispatcher.IO){
        _viewState.update { it.copy(checked = true) }
    }

    viewModelScope.launch(Dispatcher.Default){
        _viewSate.update { it.copy(content = "업데이트가 이거야?") }
    }
}

 

사실 그냥 이렇게만 보면 그래서 update 가 왜? 라는 의문이 든다.

 

update 함수를 까보면 아래와 같다.

public inline fun <T> MutableStateFlow<T>.update(function: (T) -> T) {
    while (true) {
        val prevValue = value
        val nextValue = function(prevValue)
        if (compareAndSet(prevValue, nextValue)) {
            return
        }
    }
}

바뀌기전 이전 값을 알고 있고 compareAndSet 함수를 사용해서

새로운 값을 넣기전에 다른 코루틴이나 스레드가 이전 값을 변경한건지 체크를 한다.

if문이 false 면 값을 실제로 변경 할 수 있는 조건이 될때까지 loop 를 돌게 되고

변경 할 수 있게 됐을때 변경하고 update 가 된다.

 

참고로 compareAndSet  함수는 현재 값을 기대값과 원자적으로 비교하고 기대값과 같으면 업데이트를 하고true 를 반환하고 아니면 false를 반환하는 함수다.

 

 

 

 

 

 

반응형
Comments