[TIL-230626] Android Flow 알아보기 - 1

반응형

안녕하세요
6월 말이 되면서 계속 더워지고 있고, 지쳐서 공부에 소홀해지기 쉬운데,
하루에 단 30분이라도 꾸준히 작성하자는 마인드가 필요해보입니다 

 

오늘은 Android Flow에 관해서, 포스팅을 작성해보려 합니다.
(아래는 Flow와 관련은 없지만 이미지를 넣고싶어서 넣어봤습니다)


Flow란?

 

  • 비동기적으로 실행될 수 있는 데이터 스트림

Flow의 주요한 개념은

  • 순차적으로 여러 값을 출력, 단일 값만을 출력하는 suspend function과 비교할 수 있습니다.
  • 예를들어, Flow를 사용하여 DB로부터 실시간 업데이트를 받을 수 있습니다.
  • Flow에 선언된 타입은 출력된 값과 같은 타입입니다. (ex) Flow<Int>는 integer 값을 출력하는 Flow 입니다)
  • 순차적인 값을 출력하는 Iterator와 매우 유사하지만, suspend function을 사용하여 비동기로 값을 생산, 소비합니다
  • 즉, Flow는 메인 스레드에서 차단하지 않고, 다음 값을 생산하기 위해 네트워크 요청을 안전하게 만들수 있습니다.
  •  
Flow의 세가지 요소

 

출처 :&nbsp;https://developer.android.com/kotlin/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은 아래의 포스팅 참고
 

[TIL-230625] Android Coroutine 알아보기

안녕하세요 오늘은 Kotlin의 Coroutine에 대해서 간략하게 포스팅 해보겠습니다. Coroutine 이란? 비동기로 실행되는 코드를 단순화하기 위해 Android에서 사용할 수 있는 동시성 디자인 패턴 메인 스레

weirddev.tistory.com

  • 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에 대해 알아보았습니다

잘못된 내용이 있다면 댓글 부탁드리고, 내용이 좋았다면 공감, 구독 부탁드려요!



 

반응형