[Kotlin Flow] 예제를 활용해 쉽게 Flow에 대한 개념 익히기 -1-

2022. 7. 29. 17:16개발/[Kotlin] 안드로이드 개발

반응형

개념

Coroutine에서 Flow는 suspend func(정지 함수)와는 다르게 여러 값을 순차적으로 내보낼 수 있는 유형입니다.

이렇게 말하면 어떤말인지 잘 모를 수 있습니다.(저도 그랬거든요..ㅎㅎ)

간단한 예를 보겠습니다.

Coroutine suspend Function

 val intList = ArrayList<Int>()
        val job1 = lifecycleScope.launch {
            (1..99).forEach {
                intList.add(it)
                delay(10L)
            }
        }
        lifecycleScope.launch {
            job1.join()
            intList.forEach {
                Log.d("TAG", it.toString())
            }
        }
 // result
빌드 후 약 1초 후에 모든 값이 한 번에 찍힙니다.

위 코드를 보고 결과를 예상해보세요.

 job1.join() 연산자를 걸어줬기 때문에 job1이 다 끝날 때까지 job1.join()에 멈춰있을겁니다.

그리고 job1의 스코프가 다 끝나면 intList의 로그를 찍습니다.

정지함수는 이렇게 어떤 활동이 다 끝날때까지 기다리고 다음 작업이 실행됩니다. 

그렇다면 Flow는 어떨까요?

코루틴의 정지함수가 하나의 job을 완료하고 값을 내보냈다면 flow는 (1..99)라면 1,2,3,4 ~~ 여러 값을 내보냅니다.

onCreate() {
lifecycleScope.launch {
  testFlow().collect {
  Log.d("TAG", it.toString())
 }
}
}
  private fun testFlow(): Flow<Int> = flow {
        (1..100).forEach {
            emit(it)
            delay(100L)
        }
    }
// result
1 // 0.1초 후
2 // 0.1초 후
3 // 0.1초 후
4 // 0.1초 후

Flow 예제는 일부러 100딜레이(0.1초)를 줘서 눈으로 쉽게 확인할 수 있게끔 하였습니다.

Android Studio에서 직접 코드를 복사해서 눈으로 확인해보세요 !

특징

Flow는 Cold Stream으로 동작하며 데이터를 요청할 때마다 처음부터 새로 발행됩니다. 요청의 예시는 collect, collectIndexed등이 있습니다.

Flow에게 데이터 요청

- Flow는 Coroutine의 extension이기 때문에 Coroutine 내부에서 사용되어야한다.

Flow에게 데이터 요청을 위한 함수는 주로 collect, collectIndexed, collectLatest, launchIn이 있다.

// collect
(1..3).asFlow().collect {
   delay(100)
   Log.d("TAG", "$it")
}
// result
1 // 0.1초후
2 // 0.1초후
3 // 0.1초후

collect는 Flow의 데이터를 순차적으로 가져와 하나씩 처리한다.

// collectIndexed
(1..3).asFlow().collectIndexed {
delay(100L)
Log.d("TAG", "index는 $index, value는 $value")
}
// result
index는 0, value는 1
index는 1, value는 2
index는 2, value는 3

collectIndexed는 value 뿐만아니라 index까지 받아서 처리할 수 있다.

// collectLatest
(1..3).asFlow().collectLatest {
 delay(100L)
 Log.d("TAG", "$it")
}
// result
3

collectLatest 는 가장 최근의 데이터를 가져와서 처리한다.

FLOW 취소하기

  val job = CoroutineScope(Dispatchers.IO).launch {
  (1..3).asFlow().collect {
  Log.d("TAG", "이거인가 $it")
  }
}
job.cancel()

Flow는 취소와 관련된 함수는 따로 제공하지 않기 때문에 외부에 취소가능한 무언가로 감싸줘야한다.

launch, async 등이 적절한 예시이다.

 

CoroutineContext 변경하기

  (1..3).asFlow().flowOn(Dispatchers.IO).collect {
    Log.d("TAG", "$it")
}

기존 코루틴이 withContext(Dispatchers.IO)와 같은 코드로 context를 변경했지만

Flow는 flowOn()을 통해서 변경할 것을 권장하고 있다.

반응형