안드로이드에서 다양한 Flow를 다루다보면 자주 마주치게 되는 함수들이다.
무슨 차이가 있는 것일까?
collect는 모든 값을 순차적으로 emit하며, 각 값이 완전히 처리될 때까지 다음 값을 대기한다.
예시를 보도록 하자.
fun main() {
val countDownFlow = flow{
val initialValue = 10
var currentValue = initialValue
println("emitting value : $currentValue at ${formatter.format(System.currentTimeMillis())}")
emit(initialValue)
while(currentValue > 0) {
delay(1000L)
currentValue--
println("emitting value : $currentValue at ${formatter.format(System.currentTimeMillis())}")
emit(currentValue)
}
}
collectFlow(countDownFlow)
}
1초마다 숫자를 내림차순으로 발행하는 Flow가 있다.
fun collectFlow(countDownFlow: Flow<Int>) {
runBlocking {
countDownFlow.collect{ time ->
delay(1500L)
println("collected value : $time at ${formatter.format(System.currentTimeMillis())}")
}
}
}
collect는 1.5초마다 이루어진다고 한다면 결과는 어떻게 될까?
emitting value : 10 at 18:00:39.333
collected value : 10 at 18:00:40.977
emitting value : 9 at 18:00:41.999
collected value : 9 at 18:00:43.512
emitting value : 8 at 18:00:44.517
collected value : 8 at 18:00:46.026
emitting value : 7 at 18:00:47.040
collected value : 7 at 18:00:48.541
emitting value : 6 at 18:00:49.557
collected value : 6 at 18:00:51.062
emitting value : 5 at 18:00:52.070
collected value : 5 at 18:00:53.576
emitting value : 4 at 18:00:54.584
collected value : 4 at 18:00:56.100
emitting value : 3 at 18:00:57.103
collected value : 3 at 18:00:58.615
emitting value : 2 at 18:00:59.619
collected value : 2 at 18:01:01.128
emitting value : 1 at 18:01:02.136
collected value : 1 at 18:01:03.643
emitting value : 0 at 18:01:04.646
collected value : 0 at 18:01:06.159
보다 싶이 emit으로부터 collection까지, collect가 이루어지는 블록의 소요시간인 1.5초가 걸리는 것을 볼 수 있다.
또한, collect의 딜레이가 Flow 블록의 딜레이보다 길더라도 모든 값이 순차적으로 emit되며, collection 왈료로부터 emit까지 Flow의 딜레이인 1초가 걸린다는 것을 알 수 있다.
즉, collect를 사용하면 Flow가 값을 emit했을 때 collect가 완료되기 전까지 suspend되고 완료되면 다시 루프를 수행한다.
collectLatest는 가장 최신 값만 수집하며, 새 값이 오면 이전 처리를 취소하고 최신 값으로 덮어쓴다.
동일한 Flow에 대해서 collectLatest를 예시로 들어보자.
fun collectLatestFlow(countDownFlow: Flow<Int>) {
runBlocking {
countDownFlow.collectLatest{ time ->
delay(1500L)
println("collected latest value : $time at ${formatter.format(System.currentTimeMillis())}")
}
}
}
단순히 collect를 collectLatest로 바꾼 코드이다.
emitting value : 10 at 18:01:06.371
emitting value : 9 at 18:01:07.399
emitting value : 8 at 18:01:08.428
emitting value : 7 at 18:01:09.430
emitting value : 6 at 18:01:10.433
emitting value : 5 at 18:01:11.448
emitting value : 4 at 18:01:12.453
emitting value : 3 at 18:01:13.464
emitting value : 2 at 18:01:14.472
emitting value : 1 at 18:01:15.478
emitting value : 0 at 18:01:16.489
collected latest value : 0 at 18:01:17.994
collect와는 달리, 마지막으로 emit된 값이 처리된 것을 볼 수 있다.
이것은 emit에 걸리는 딜레이 1초보다 collect에 걸리는 딜레이가 1.5초로 더 길기 때문에 10이 emit되어 collect가 수행되고 있는 도중에 다시 9가 emit되면 기존의 10에 대한 작업이 취소된다.
따라서 더이상 emit할 값이 없어서 작업이 취소되지 않는 0만이 제대로 collect된 것을 볼 수 있다.
즉, collectLatest는 collect와 달리 emit에서 Flow가 suspend되지 않는다.(정확히는 값을 보내고 바로 넘어가는 것)
순차적으로 모든 값이 collect 되는 것을 보장하기 때문에, 모든 값이 처리가 되어야하는 데이터 저장, 통신 등에서 사용된다.
이전 값에 상관없이 빠르게 가장 최신의 값만을 처리하기 때문에, 값이 자주 바뀌면서 이전 값이 필요 없는 UI 상태를 반영할 때 자주 사용된다.