안드로이드 앱을 개발하다보면 EditText
를 이용한 검색 기능을 많이 구현합니다.
하지만 EditText
에서 입력값의 변화를 감지할 때마다 API 호출을 하게되면 많은 비용을 소비하게 됩니다.
예를 들어 빠르게 값을 입력하고 지웠다면, 불필요한 입력에도 API를 호출하여 매우 비효율적이라 할 수 있습니다.
그러므로 일정 시간 간격을 주고, 유저의 입력이 끝났다고 판단될 때 API 호출하여 좀 더 효율적으로 구현해야 합니다.
이때 사용하는 것이 debounce 기법입니다.
debounce란?
debounce는 스크롤 또는 값의 입력과 같이 이벤트가 과도하게 많은 API를 호출할 경우 지정한 시간 동안 호출의 제약을 걸어 과부하를 방지하는 기술입니다.
예를 들어 지정한 시간을 1초라고 할 때, 이 1초 동안 사용자로부터 5번의 입력이 들어왔다고 가정하겠습니다.
debounce를 사용하면 1초 후, 5번의 입력 중 가장 마지막 입력에 대한 API를 호출해주면 됩니다.
debounce의 구현
debouce는 RxJava
, Coroutine
과 같은 비동기 라이브러리를 사용하여 구현할 수 있습니다.
오늘은 Coroutine
의 Flow
를 이용한 구현 방법을 알아보도록 하겠습니다.
먼저 callbackFlow
를 생성하여, UI로 부터 이벤트가 발생할 때마다 데이터의 흐름을 전송해줍니다.
콜백을 받기 위해 EditText
의 addTextChangedListener
를 정의합니다.
만약 ImageView
클릭의 경우에는 setOnClickListener
를 정의해주면 되겠죠?
(callbackFlow
가 사라질 때까지 반복됩니다.)
fun EditText.textChangedFlow(): Flow<CharSequence?> = callbackFlow {
addTextChangedListener { text -> trySend(text) }
awaitClose { addTextChangedListener(null) }
}
이후 생성한 Flow(데이터 흐름)을 구독합니다. 이때 중간 연산자를 이용해 debounce()
를 호출해줍니다.
이외에도 filter()
와 같은 함수를 이용하면 원하는대로 값을 필터링해서 받을 수 있습니다.
@OptIn(FlowPreview::class)
private fun setSearchDebounce() = CoroutineScope(Dispatchers.IO).launch {
binding.etSearch.textChangedFlow()
.debounce(500)
.filter { text -> !text.isNullOrEmpty() }
.onEach { text -> searchUser(text.toString()) }
.collect()
}
만약 하나의 Coroutine Scope에서 여러 개의 이벤트를 감지하고 있다면,collect()
대신 launchIn()
를 통해 새로운 코루틴을 생성해 처리하면 됩니다.
(launchIn()
의 파라미터로 현재의 Coroutine Scope를 지정)
'Android' 카테고리의 다른 글
[안드로이드 / Kotlin] FusedLocationProviderClient (0) | 2023.05.25 |
---|---|
[안드로이드 / Kotlin] 둥근 모서리 Bitmap 이미지 만들기 (0) | 2022.11.18 |
[안드로이드 / Kotlin] RecyclerView 최상단 최하단 스크롤감지 (0) | 2022.11.11 |
[안드로이드 / Kotlin] Snackbar에 커스텀 폰트 적용하기 (0) | 2022.11.08 |
[안드로이드] ConstraintLayout 뷰 밀림 문제 (0) | 2022.10.30 |