오늘도 더 나은 코드를 작성하였습니까?

단일값을 보내는 flow 와 flow의 결합. 본문

Coroutine/coroutineFlow

단일값을 보내는 flow 와 flow의 결합.

hik14 2021. 5. 31. 16:13

단일값을 보내는 flow 

// plantsListSortOrderCache.getOrAwait()는 flow<List<Plant>> 반환.
private val customSortFlow = flow { emit(plantsListSortOrderCache.getOrAwait()) }
// Create a flow that calls a single function
private val customSortFlow = plantsListSortOrderCache::getOrAwait.asFlow()

getOrAwait를 호출하고 결과를 첫 번째이자 유일한 값으로 내보내는 새 Flow를 만듭니다. 

::을 사용하여 결과 Function 객체에서 asFlow를 호출하는 getOrAwait 메서드를 참조하면 됩니다.

두 코드는 모두 동일한 작업을 합니다. getOrAwait를 호출하고 결과를 내보낸 후 완료합니다

 

 

두 flow의 결합시키기

// retrofit.kt
interface SunflowerService {
    @GET("googlecodelabs/kotlin-coroutines/master/advanced-coroutines-codelab/sunflower/src/main/assets/plants.json")
    suspend fun getAllPlants() : List<Plant>

    @GET("googlecodelabs/kotlin-coroutines/master/advanced-coroutines-codelab/sunflower/src/main/assets/custom_plant_sort_order.json")
    suspend fun getCustomPlantSortOrder() : List<Plant>
}



suspend fun customPlantSortOrder(): List<String> = withContext(Dispatchers.Default) {
        val result = sunflowerService.getCustomPlantSortOrder()
        result.map { plant -> plant.plantId }
    }



// repository.kt
    
private val customSortFlow =  plantService::customPlantSortOrder().asFlow()


//    customSortFlow 결과가 나오면 위의 flow 의 값( plantDao.getPlantsFlow())에 최신 값과 결합합니다
//    따라서 두 'plants' 와 `sortOrder`는 초기 값 (flow 가 하나 이상의 값을 내보냈다면)이 있다면,
//    모든 변경사항이 `plants` 또는`sortOrder`는 `plants.applySort (sortOrder)를 호출한다.

val plantsFlow: Flow<List<Plant>>
   get() = plantDao.getPlantsFlow()
       .combine(customSortFlow) { plants, sortOrder ->
       	  // plants 는 데이터베이스에서 가져오고
          // 정렬순서는 네트워크 통신을 통해 받아온다. 
          plants.applySort(sortOrder)
       }   

 

 

combine 연산자는 두 flow을 결합합니다.

두 flow 모두 자체 코루틴에서 실행되고, 각 flow에서 새 값이 생성될 때마다 각 흐름의 최신 값으로 변환이 호출됩니다.

combine을 사용하면 캐시된 네트워크 조회를 데이터베이스 쿼리와 결합할 수 있습니다.

 

두 가지 모두 서로 다른 코루틴에서 동시에 실행됩니다. 즉, 데이터베이스에서 qurey 요청을 시작하는 동안 Retrofit에서 네트워크 쿼리를 시작할 수 있습니다. 그런 다음 두 flow 모두에서 결과가 나오는 즉시 combine 람다를 호출하여 로드된 식물에 로드된 정렬 순서를 적용합니다.

 

combine 변환은 결합되는 flow별로 코루틴을 하나씩 실행합니다. 따라서 두 흐름을 동시에 결합할 수 있습니다.

flow을 '공정한' 방식으로 결합합니다. 즉,  하나의 flow가 tight loop(CPU 및 IO처리를 많이 반복하는)에서 생성되더라도 모두 값을 생성할 기회가 있습니다.

 

combine 연산자의 작동 방식을 살펴보기.

 onStart에 상당한 지연을 포함하여 두 번 내보내도록 다음과 같이 customSortFlow를 수정합니다.

private val customSortFlow = plantsListSortOrderCache::getOrAwait.asFlow()
   .onStart {
       // 먼저 빈 리스트 내보냄.
       emit(listOf())
       // 5초 지연.
       delay(5000)
   }

 

onStart  -  transform은 관찰자가 다른 연산자 이전에 값을 수신하면 발생합니다. placeholder values를 내보낼 수 있습니다.

위 코드는 빈 목록을 내보내고 getOrAwait 호출을 1,500밀리초 지연한 후에 원래 흐름을 계속합니다.

지금 앱을 실행하면 Room 데이터베이스 쿼리가 즉시 반환되어 빈 목록과 결합됩니다(알파벳순으로 정렬됨).

그런 다음 약 5000밀리초 후에 맞춤 정렬이 적용됩니다.

 

onStart를 사용하여 flow이 실행되기 전에 suspend 코드를 실행할 수 있습니다. flow에 추가 값을 내보낼 수도 있으므로이를 사용하여 네트워크 요청 흐름에서 Loading 상태를 내보낼 수 있습니다.

 

 

'Coroutine > coroutineFlow' 카테고리의 다른 글

Flow를 사용한 동시 실행 제어  (0) 2021.05.31
Flow를 사용한 스타일 혼합  (0) 2021.05.31
flow을 사용한 비동기 작업  (0) 2021.05.31
flow의 실행 방법  (0) 2021.05.31
stateFlow sharedFlow  (0) 2021.05.27