개발일지

Android in A..Z - Flow 본문

Android (안드로이드)

Android in A..Z - Flow

강태종 2021. 8. 5. 14:10

Flow

Flow는 Coroutine에서 여러 값을 순차적으로 보내는 유형입니다. Jetpack에서도 많이 쓰이는 유형이고, Iterator와 비슷하며 map, filter등 람다 함수를 지원하면서 suspend 함수에서 쓰이기 때문에 비동기 처리에 효율적입니다.


Flow 구성

Flow

  • Producer : Flow Builder에서 비동기적으로 데이터를 생산한다.
  • Intermediary : Stream에서 보내는 데이터를 소비하지 않고 수정한다.
  • Consumer : 값을 사용한다.

Producer

Flow Builder를 통해 만든다. flow, channelFlow등 다양한 함수가 존재한다. Builder를 통해 Data를 만들고 emit을 통해 Data를 전달한다. Consume하는 함수가 수행될 때마다 Flow Builder가 수행되고 emit되는 값을 소비한다.

    val data = flow {
        doLog("Flow Start")
        repeat(3) {
            delay(500L)

            doLog("Emit : $it")
            emit(it)
        }
        doLog("Flow End")
    }

Intermediary

map, filter같은 람다 함수로 Flow에서 값을 수정할 수 있습니다.

    viewModel.data.map {
        it + 10
    }.filter {
        it > 0
    }.onEach {
        viewModel.doLog("Map -> onEach : $it")
    }.collect {
        viewModel.doLog("Map -> onEach -> Collect : $it")
    }

Consumer

single, first, collect 등이 있다.

    viewModel.data.collect { 
        viewModel.doLog("Collect $it") 
    }
    viewModel.data.first {
        viewModel.doLog("First $it")
        true

        // False면 다시 받아온다.
        // NoSuchElement 발생 가능성 있음
    }
    viewModel.doLog("First End")
  • first : 반환형이 true인 첫번째 값, first()를 통해 무조건 첫번재 값을 받을 수 있다. emit된 값이 없거나 true를 만족하는 값이 없으면 Exception 발생
  • single : Flow에서 emit된 값이 한개일 때 반환, emit된 값이 여러개면 Exception 발생
  • collect : emit될 때마다 수행

Exception Controll

215

만약 Flow Builder에서 Exception이 발생한 경우, Flow Builder는 즉시 종료된다. 그리고 catch블록이 있으면 실행되는데 Flow를 수정할 수 있다.

    val exceptionData = flow {
        doLog("Exception Flow Start")
        repeat(10) {
            delay(500L)
            if (it > 3) {
                throw Exception("Exception : $it")
            }

            emit(it)
        }
    }
    viewModel.exceptionData.catch {
        viewModel.doLog(it.message)
        emit(10)
    }.collect {
        viewModel.doLog("Exception Collect : $it")
    }

다른 CoroutineContext에서 실행하기

flowOn을 통해 Flow Builder의 CoroutineContext를 수정할 수 있다.

    val flowOn = flow {
        repeat(10) {
            delay(500L)
            doLog("Channel Flow Send : $it")
            emit(it)
        }
    }.onEach {
        log.value += "FlowOn In ViewModel : $it"
    }.flowOn(Dispatchers.Main) // ↑ Dispatchers.Main 영향을 받음

정리

기존의 suspend 함수는 함수의 실행이 종료되야 값을 한번에 반환한다. 즉 List같은 형식으로 값을 반환할 경우 List를 만들고 한번에 값을 반환한다. 하지만 Flow는 값을 emit하고 collect하는 과정에서 하나씩 받아올 수 있는 장점이 있는 것 같다.


Git (예제 코드)

https://github.com/KangTaeJong98/Example/tree/main/Android/Flow

 

GitHub - KangTaeJong98/Example: My Example Code

My Example Code. Contribute to KangTaeJong98/Example development by creating an account on GitHub.

github.com

 

Comments