Flow 및 main-safe
Flow는 main-safe functions를 호출해야 된다.
코루틴의 일반적인 main-safe 보장을 유지합니다. Room과 Retrofit에서는 main-safe 안전성이 보장되므로 Flow를 사용한 네트워크 요청이나 데이터베이스 쿼리를 실행하기 위해 다른 조치를 취할 필요가 없습니다.
- plantService.customPlantSortOrder가 Retrofit 스레드에서 실행됨(Call.enqueue 호출)
- getPlantsFlow가 Room Executor에서 쿼리를 실행함
- applySort가 수집 디스패처(이 경우 Dispatchers.Main)에서 실행됨
Retrofit에서 suspend 함수를 호출하고 Room에서 flow을 사용했다면 main-safe을 우려하여 이 코드를 복잡하게 만들 필요가 없습니다. 그러나 데이터 세트의 규모가 커질수록 applySort 호출 시 기본 스레드를 차단할 정도로 속도가 떨어질 수도 있습니다.
Flow는 flowOn이라는 선언적 API를 제공하여 흐름이 실행되는 스레드를 제어합니다.
val plantsFlow: Flow<List<Plant>>
get() = plantDao.getPlantsFlow()
.combine(customSortFlow) { plants, sortOrder ->
plants.applySort(sortOrder)
}
.flowOn(defaultDispatcher)
.conflate()
flowOn을 호출하면 코드 실행 방식에 중요한 두 가지 영향을 미칩니다.
- defaultDispatcher(이 경우 Dispatchers.Default)에서 새 코루틴을 실행하여 flowOn을 호출하기 전에 flow을 실행하고 수집한다
- 버퍼를 도입하여 새 코루틴의 결과를 이후 호출로 전송합니다.
- 이 버퍼의 값을 flowOn 이후의 Flow에 내보냅니다. 이 경우에는 ViewModel에 있는 asLiveData입니다.
flowOn은 withContext가 디스패처를 전환하기 위해 작동하는 방식과 매우 유사하지만 변환 도중에 flow의 작동 방식을 변경하는 버퍼가 도입된다는 점에 차이가 있습니다. flowOn에서 실행된 코루틴은 호출자가 소비하는 속도보다 빠르게 결과를 생성할 수 있으며 기본적으로 다량의 결과를 버퍼링합니다.
여기서는 결과를 UI에 전송할 계획이므로 최근 결과에만 관심이 있습니다. 이것이 conflate 연산자의 역할입니다.
이 연산자는 마지막 결과만 저장하도록 flowOn의 버퍼를 수정합니다.
이전 결과를 읽기 전에 다른 결과가 제공되면 이전 결과를 덮어씁니다.
flowOn - 이전까지의 flow을 수집하는 새 코루틴을 실행하고 결과를 작성하는 버퍼를 도입합니다.
conflate - 생성된 마지막 값만 버퍼에 저장하도록 지시하는 conflate와 같은 더 많은 연산자를 사용하여 버퍼를 제어할 수 있습니다.
많은 양의 메모리 버퍼링 결과를 사용하기가 쉽기 때문에 flowOn을 데이터베이스 결과와 같은 큰 객체와 함께 사용할 때는 버퍼를 알고 있어야 합니다.