2023. 1. 30. 23:26ㆍAndroid Jetpack
- Flow 란?
- suspend 가능한 "Iterator"
-코루틴에서 Flow(흐름)은 단일 값만 반환하는 정지 함수와 달리 여러 값을 순차적으로 내보낼 수 있는 유형입니다.
예를 들면 Flow을 사용하여 데이터베이스에서 실시간 업데이트를 수신할 수 있습니다.
-Flow는 코루틴을 기반으로 빌드되며 여러 값을 제공할 수 있습니다.
-Flow는 비동기식으로 계산할 수 있는 데이터 스트림의 개념입니다. 내보낸 값은 동일한 유형이어야 합니다.
예를 들어 Flow<Int>는 정수 값을 내보내는 Flow입니다.
- 생산자는 스트림에 추가되는 데이터를 생산합니다. 코루틴 덕분에 흐름에서 비동기적으로 데이터가 생산될 수도 있습니다. (데이터 생성)
- (선택사항) 중개자는 스트림에 내보내는 각각의 값이나 스트림 자체를 수정할 수 있습니다.(데이터 변환)
- 소비자는 스트림의 값을 사용합니다.(데이터 저장 불가)
출처:Android의 Kotlin 흐름 | Android 개발자 | Android Developers
Android의 Kotlin 흐름 | Android 개발자 | Android Developers
Android의 Kotlin 흐름 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 코루틴에서 흐름은 단일 값만 반환하는 정지 함수와 달리 여러 값을 순차적으로 내보낼
developer.android.com
- Flow 와 Livedata 차이?
- Flow와 StateFlow
Flow을 이용할때는 화면이 재구성될때 마다 다시 서버 혹은 DB로 부터 데이터를 가져오거나
repository로부터 데이터를 전달받아 ViewModel에 저장해놓고 사용을햇다.
Viewmodel은 onDestory가 호출 되도 저장해둔 데이터가 살아있기때문에 Viemodel에서 해당 데이터를 저장하고있으면 문제가없다.
그런데 왜 Stateflow가 나온걸까.. Flow의 한계를 해결하기위해 등장한것이다
StateFlow는 데이터 홀더(저장소) 역할을 하면서 Flow의 최적으로 상태 업데이트를 내보내고 여러 소비자에게 값을 내보낼 수 있는 Flow Api 입니다.
출처:Migrating from LiveData to Kotlin’s Flow | by Jose Alcérreca | Android Developers | Medium
Migrating from LiveData to Kotlin’s Flow
In this post you’ll learn how to expose Flows to a view, how to collect them, and how to fine-tune it to fit specific needs.
medium.com
- StateIn을 사용하여 Flow를 stateFlow로 변환해보기.
- stateIn내부는 다음과 같다.
public fun <T> Flow<T>.stateIn(
scope: CoroutineScope,
started: SharingStarted,
initialValue: T
): StateFlow<T> {
val config = configureSharing(1)
val state = MutableStateFlow(initialValue)
val job = scope.launchSharing(config.context, config.upstream, state, started, initialValue)
return ReadonlyStateFlow(state, job)
}
stateIn은 세가지 변수를 받는다.
- scope: StateFlow가 Flow부터 데이터를 구독받은 CoroutineScope을 명시한다
- started: Flow로부터 언제부터 구독을 할지 명시할수있다.
- initialValue: StateFlow에 저장될 초기값을 설정한다.
package com.example.kakaobook.ui.view.ui.view.viewmodel
import android.annotation.SuppressLint
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.kakaobook.ui.view.data.model.Book
import com.example.kakaobook.ui.view.data.model.SearchResponse
import com.example.kakaobook.ui.view.repository.BookSearchRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class BookSearchViewModel(
private val bookSearchRepository: BookSearchRepository
) : ViewModel() {
//Api
private val _searchResult = MutableLiveData<SearchResponse>()
val searchResult: LiveData<SearchResponse> = _searchResult
// 코루틴 백그라운드 작업을 용이하게함.
@SuppressLint("SuspiciousIndentation")
fun searchBooks(query: String) = viewModelScope.launch(Dispatchers.IO) {
val response = bookSearchRepository.searchBooks(query, "accuracy", 1, 20)
if (response.isSuccessful) {
response.body()?.let {
_searchResult.postValue(it)
}
}
}
//Room
fun saveBook(book: Book) = viewModelScope.launch(Dispatchers.IO) {
bookSearchRepository.insertBooks(book)
}
fun deleteBook(book: Book) = viewModelScope.launch(Dispatchers.IO) {
bookSearchRepository.deleteBooks(book)
}
//StateFlow
val favoriteBooks:StateFlow<List<Book>> = bookSearchRepository.getFavoriteBooks()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), listOf())
}
Room 응답을 flow 에서 stateflow로 변환하도록햇다.
statein을 통해 StateFlow가 Flow부터 데이터를 구독받은 viewmodelscope를 명시하고,
SharingStared.whileSubscribed(5000)은 5초의 지연을 추가한후 구독자가없으면 코루틴을 중지합니다.
초기값은List<Book>인데 listof()형식이기때문에 넣어주면된다.
그러면 이제 ui에서 구독하면된다.
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
bookSearchViewModel.favoriteBooks.collectLatest {
bookSearchAdapter.submitList(it)
}
}
}
'Android Jetpack' 카테고리의 다른 글
데이터 바인딩 - 좋아요 카운트 앱 만들어보기 (0) | 2023.02.16 |
---|---|
계산기 만들어보기 (Livedata+ViewModel+DataBinding+BindingAdapter) (0) | 2023.02.15 |
Room DB를 UI와 연동하기 (0) | 2023.01.30 |
책 검색결과 저장을 위한 Room DB 구현해보기 (0) | 2023.01.27 |
Safe args로 Fragment 간 데이터 전달하기 (1) | 2023.01.26 |