반응형
안녕하세요
6월 말이 되면서 계속 더워지고 있고, 지쳐서 공부에 소홀해지기 쉬운데,
하루에 단 30분이라도 꾸준히 작성하자는 마인드가 필요해보입니다
오늘은 Android Flow에 관해서, 포스팅을 작성해보려 합니다.
(아래는 Flow와 관련은 없지만 이미지를 넣고싶어서 넣어봤습니다)
Flow란?
- 비동기적으로 실행될 수 있는 데이터 스트림
Flow의 주요한 개념은
- 순차적으로 여러 값을 출력, 단일 값만을 출력하는 suspend function과 비교할 수 있습니다.
- 예를들어, Flow를 사용하여 DB로부터 실시간 업데이트를 받을 수 있습니다.
- Flow에 선언된 타입은 출력된 값과 같은 타입입니다. (ex) Flow<Int>는 integer 값을 출력하는 Flow 입니다)
- 순차적인 값을 출력하는 Iterator와 매우 유사하지만, suspend function을 사용하여 비동기로 값을 생산, 소비합니다
- 즉, Flow는 메인 스레드에서 차단하지 않고, 다음 값을 생산하기 위해 네트워크 요청을 안전하게 만들수 있습니다.
Flow의 세가지 요소
- Producer : 스트림으로 추가할 데이터를 생산합니다. 비동기로 생산 가능합니다.
- Intermediaries(선택적) : 스트림이나 스트림 자체에서 출력된 각각의 값을 수정할 수 있습니다.
- Consumer : 스트림으로부터 전달된 값을 소비합니다.
코드 작성해보기
1. Flow 생성
class NewsRemoteDataSource(
private val newsApi: NewsApi,
private val refreshIntervalMs: Long = 5000
) {
val latestNews: Flow<List<ArticleHeadline>> = flow {
while(true) {
val latestNews = newsApi.fetchLatestNews()
emit(latestNews) // Flow로 요청된 결과를 출력
delay(refreshIntervalMs) // 일정시간 중지
}
}
}
// suspend function 을가지고 네트워크 요청을 제공하는 인터페이스
interface NewsApi {
suspend fun fetchLatestNews(): List<ArticleHeadline>
}
- flow 빌더 함수 내 emit 함수를 사용하여 값을 데이터 스트림에 출력할 수 있는 Flow를 만듭니다.
- Producer가 coroutine에 존재하여, suspend function이 리턴될 때 까지 정지상태로 유지됩니다.
* coroutine은 아래의 포스팅 참고
- Producer가 다른 CoroutineContext의 값을 emit할 수 없습니다. 이런 경우 callbackFlow 같은 다른 Flow 빌더를 사용할 수 있습니다.
2. 스트림 수정
- Intermediaries 값을 소비하지 않고 중간 연산를 활용하여 스트림을 수정할 수 있습니다.
class NewsRepository(
private val newsRemoteDataSource: NewsRemoteDataSource,
private val userData: UserData
) {
/**
* Flow을 변환 시켜 좋아하는 최신 뉴스를 출력 (lazy하고 Flow를 trigger 하지 않음)
* 해당 시점에 Flow에서 출력된 값입니다.
*/
val favoriteLatestNews: Flow<List<ArticleHeadline>> =
newsRemoteDataSource.latestNews
// 즐겨찾는 주제 목록을 필터링하는 중간 연산 작업
.map { news -> news.filter { userData.isFavoriteTopic(it) } }
// 최신 뉴스를 캐시에 저장하는 중간 연산 작업
.onEach { news -> saveInCache(news) }
}
- 위의 코드는 중간 연산으로 map을 사용하여 좋아하는 최신 뉴스의 목록을 반환합니다.
- 중간 연산이 많아질 수록 느려질 수 있습니다.
3. Flow로부터 수집
- 터미널 연산자를 사용하여 Flow를 트리거 후 값 수신을 시작합니다.
* 터미널 연산자 : 일시 중단 함수(collect , single , reduce , toList 등)이거나 지정한 스코프에서 flow를 수집을 시작(launchIn)하는 연산자 - Flow를 출력하여 스트림에 모든 값을 얻기 위해 collect를 사용합니다.
- collect
- suspend function이고 coroutine 안에서 실행해야 합니다.
- 모든 새 값에서 호출되는 매개변수로 람다를 사용합니다.
- 일시 중단 기능이므로, collect를 호출하는 coroutine은 Flow가 끝날 때 까지 정지합니다.
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
init {
viewModelScope.launch {
// Flow를 트리거하고 collect를 사용하여 element를 소비합니다.
newsRepository.favoriteLatestNews.collect { favoriteNews ->
// 최신 인기뉴스 보기 업데이트 코드
}
}
}
}
- collect은 최신 뉴스를 새로고침하는 생산자를 트리거합니다.
- 또한, 고정된 간격으로 네트워크 요청의 결과를 출력합니다.
- 1. Flow 생성 에서 producer가 while(true) 인 상태이므로, ViewModel이 초기화되고, viewModelScope가 취소된다면, 데이터의 스트림은 닫힙니다.
- Flow collection의 중지 조건
- collect 하는 coroutine이 취소되면, producer도 같이 멈추게 됩니다.
- producer가 출력을 종료하였을 때, 데이터 스트림이 닫히고, collect를 호출한 coroutine이 재 실행합니다.
- Flow는
- 다른 중간 연산자가 없으면, cold 하고 lazy 하다
- producer는 터미널 연산자가 Flow에서 호출될 때 마다 producer 코드가 실행된다는 의미
** 남은 내용은 다음 포스팅에서 이어집니다.
이번에는 Kotlin Flow에 대해 알아보았습니다
잘못된 내용이 있다면 댓글 부탁드리고, 내용이 좋았다면 공감, 구독 부탁드려요!
반응형
'DEV > Android' 카테고리의 다른 글
[TIL-230623] StateFlow 알아보기 (0) | 2023.06.28 |
---|---|
[TIL-230626] Android Flow 알아보기 - 2 (0) | 2023.06.27 |
[TIL-230625] Android Coroutine 알아보기 (0) | 2023.06.25 |
[TIL-230622] Retrofit 알아보기 (0) | 2023.06.22 |
[TIL-230612] 데이터 출력을 위한 List 구현 (0) | 2023.06.12 |