본문 바로가기
Projects/FineByMe

[Android/Kotlin] Jetpack Compose에서 Flow.debounce()로 검색 요청 최적화하기

by quessr 2025. 5. 7.

 

프로젝트에서 실시간 사진 검색 기능을 구현하던 중, 검색어 입력 시마다 API가 호출되는 문제가 있었습니다.
예를 들어 사용자가 "dinosaur"를 입력하면 "d", "di", "din" 등 입력하는 매 글자마다 API 요청이 발생했기 때문에 불필요한 호출이 많아지고 사용자 경험에도 영향을 주고 있었습니다.

이 문제를 해결하기 위해 Flow.debounce()를 적용해 검색 흐름을 개선해보았습니다.


문제 상황: 과도한 API 호출

처음에는 TextField의 onValueChange에서 바로 API를 호출하고 있었기 때문에, 아래와 같이 입력할 때마다 로그가 찍히고 요청이 전송되었습니다.

 

이처럼 한 글자 입력할 때마다 API 요청이 발생해 사용량이 과도하게 늘고

로딩 UI가 계속 깜빡이는 등 UX에도 부정적인 영향을 줬습니다.


debounce 적용: 입력 흐름 제어

Flow.debounce()는 지정한 시간(예: 500ms) 동안 값의 변화가 없을 때만 데이터를 흘려보내는 연산자입니다.
즉, 사용자가 입력을 멈춘 후 500ms가 지나야 API 요청이 보내지도록 동작합니다.

이를 위해 검색어 입력값을 바로 처리하지 않고 MutableStateFlow로 관리하며

ViewModel에서 다음과 같이 debounce 로직을 추가했습니다.

@OptIn(FlowPreview::class)
private fun observeSearchQuery() {
    viewModelScope.launch {
        _searchQuery
            .debounce(500)
            .distinctUntilChanged()
            .collect { query ->
                if (query.isEmpty()) {
                    _photos.value = cachedPhotos
                    _loadingState.value = LoadingState.DONE
                } else {
                    searchPhotos(query)
                }
            }
    }
}

 

이렇게 하면, 500ms 동안 입력이 없을 경우에만 그 시점의 검색어로 API가 호출됩니다.


적용 결과

debounce를 적용한 이후, "dinosaur"를 빠르게 입력해도 매 글자마다 요청이 발생하지 않고 아래처럼 일정 간격으로만 API 요청이 전송되는 것을 확인할 수 있었습니다.

 

즉, 입력이 계속해서 이어질 경우 요청이 지연되고
500ms 이상 멈춘 시점의 최종 입력값만 수집되어 API 호출이 이루어지게 됩니다.


마무리하며

Flow.debounce()는 사용자 입력이 잠시 멈췄을 때만 동작하게 해주는 기능으로
검색창이나 슬라이더처럼 빠르게 바뀌는 값에 대해 불필요한 처리를 줄이고 성능을 개선할 수 있습니다.

이번 경험을 통해 Jetpack Compose에서 ViewModel, StateFlow, debounce()를 함께 사용하면
입력 흐름을 유연하게 제어하면서도 UI와 로직을 깔끔하게 분리할 수 있다는 걸 느꼈습니다.

직접 적용해보면서 debounce 필요한지, 어떤 상황에서 효과적인지도 자연스럽게 이해할 있었던 좋은 경험이었습니다.

반응형