Kotlin: flatMapLatest

2025. 11. 7. 16:15Programming

    목차
반응형

map과의 동작 비교를 통해 flatMapLatest를 알아보겠습니다.

map 동작

map의 반환값은 flow 임
그래서 아래 코드와 같이 flow에 대해서 collect 할 수 있음

val channelFlow = flow {
    emit("A")
    delay(100)
    emit("B")
}

channelFlow.map { name ->
    name  // bypass
}.collect {
    print(it)
}

출력

A
B

flatMapLatest 동작

새로운 작업이 들어오면 이전 작업을 바로 취소하고, 최신 작업 결과만 흘려보내는 연산자.

val channelFlow = flow {
    emit("A")
    delay(1000)
    emit("B")
}

channelFlow.flatMapLatest { name ->
    flow {
        emit("$name - 1")
        delay(500)
        emit("$name - 2")
        delay(500)
        emit("$name - 3")
    }
}.collect {
    println(it)
}

출력

A - 1
A - 2
B - 1  <- A - 3 출력이 중단됨
B - 2
B - 3

검색 예제

searchText
    .flatMapLatest { keyword ->
        search(keyword)
    }
    .collect { result ->
        showResult(result)
    }

빠르게 "a" -> "ab" -> "abc"가 되면 앞의 두 개는 취소됨

여기서 flat이 붙은 이유는

fun search(query: String): Flow<String> = flow {
    emit("searching $query")
    delay(500)
    emit("result for $query")
}

fun main() = runBlocking {
    val searchText: Flow<String> = flow {
        emit("a")
        delay(200)
        emit("ab")
    }

    val result: Flow<String> = 
        searchText.map { query ->
            search(query)  // 여기서 Flow를 반환함 - 그런데 map의 반환이 Flow라서 Flow<Flow<String>>이 반환됨
        }

    result.collect { innerFlow ->  // 받는게 Flow<String> 이므로, 이걸 또 collect 해야 값을 꺼낼 수 있음
        innerFlow.collect {
            println(it)
        }
    }
}

이를 flatMapLatest를 사용하면,

fun search(query: String): Flow<String> = flow {
    emit("searching $query")
    delay(500)
    emit("result for $query")
}

fun main() = runBlocking {
    val searchText: Flow<String> = flow {
        emit("a")
        delay(200)
        emit("ab")
    }

    val result: Flow<String> = 
        searchText.flatMapLatest { query ->
            search(query)  // 평탄화 하여 반환 - 반드시 Flow<T>를 반환해야 함 (단순 값의 반환을 허용하지 않음)
        }

    result.collect {
         println(it)
    }
}

flatMapLatestsms Flow 반환 시 이를 flatten(펼쳐서) 단일 flow로 만들어 보냄

다른 예

val aflow = flowOf(1, 2, 3)

aflow.flatMapLatest { value ->
    flowOf(value, value * 2)
}

결과

3
6

1이 emit 되고 flowOf(1, 2)를 시작하자마자 다시 2가 emit 되어 이 작업이 취소됨
2의 경우도 마찬가지고 결국 3에 대해서만 flowOf(3, 6)이 수행됨

flatMapLatest는 괜히 Flow로 감싸서 전달해야 하니 번거로워 보입니다.
그러나 검색 결과 등 처럼 Flow로 반환하는 API를 사용해야 할 경우가 있으며, 이때 flatMapLatest를 사용합니다.

그렇지 않은 경우 mapLatest를 사용합니다.

정리

  • map
    • 값을 변환할 뿐, 비동기 처리 없음
  • flatMapConcat
    • 순서대로 처리함 (요청 종료 시까지 다음 요청을 수행하지 않음)
  • flatMapMerge
    • 모든 요청을 동시에 수행
  • flatMapLatest
    • 이전 요청 취소하고 최신 것만 수행
    • 검색 입력 등 최신의 값에 대해서 처리하는 것이 의미있을때 사용
반응형

'Programming' 카테고리의 다른 글

Kotlin Scope function, Receiver function  (0) 2025.11.07
오픈소스 라이센스  (0) 2022.12.13
Makefile %.o: %.cpp pattern  (0) 2022.09.29
cmake 옵션(option) 사용  (0) 2022.09.27
build shared lib on macOS  (0) 2022.09.27