# flow 實際使用的一些場合 #### 程式碼範例使用 [之前寫的side Project](https://github.com/JCChiou/bookManagerDB) 1. **Retrofit連線** * 下面是在viewModel發送網路請求的方法 * flow寫法易讀性稍高 使用coroutine寫法 ```kotlin= private fun getBookApiResponse() { val count = getApiCount.value viewModelScope.launch(Dispatchers.Main) { try { val data = count?.let { async(Dispatchers.IO) { BookApi.retrofitService.getAPIData(it) } } _response.value = data?.await() _dataFlag.value = true //送出Api request flag 準備寫入DB Timber.d("try block execute") } catch (e: Exception) { Timber.d("錯誤訊息= ${e}") } } } ``` 使用flow寫法 ```kotlin= private fun getBookApiResponse() { val count = getApiCount.value var data: Mydata? = null viewModelScope.launch { flow { data = count?.let { BookApi.retrofitService.getAPIData(it) } emit(data) Timber.d("flow emit") }.flowOn(Dispatchers.IO) .onStart { Timber.d("flow start") // throw IllegalThreadStateException("flow error") } .onCompletion { Timber.d("flow complete") _dataFlag.value = true // throw IllegalThreadStateException("flow error") } .catch { ex -> Timber.d("an error ${ex.message}") _dataFlag.value = false } .collect { _response.value = data Timber.d("flow collect") } } } ``` 2. **搭配Room使用** 使用coroutine寫法 ```kotlin= private suspend fun getBookListFromDatabase() { viewModelScope.launch { _myBookList.value = database.getBookList() _actionFinsihed.value = false } selectLock = false } //DAO @Query("SELECT * FROM my_bookstore_table") fun suspend getBookList() : List<BookStore>? ``` 使用flow寫法(這邊舉例三種寫法) A. * **將collect的值賦予liveData,用observer的方式一樣** * ***要注意DAO的function不能有suspend聲明*** [這篇有解答](https://stackoverflow.com/questions/59170415/coroutine-flow-not-sure-how-to-convert-a-cursor-to-this-methods-return-type) ```kotlin= //初始化->獲取資料庫所有資料 private fun getBookListFromDatabase() { viewModelScope.launch { database.getBookList().flowOn(Dispatchers.IO) .onStart { Timber.d("getBook list flow start") } .catch { Timber.d("getBook list flow catch error") } .onCompletion { Timber.d("getBook list flow completion") selectLock = false } .collectLatest { _myBookList.postValue(it) } } } //DAO @Query("SELECT * FROM my_bookstore_table") fun getBookList() : Flow<List<BookStore>?> ``` B. * **透過liveData Builder建立** * **需導入implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-alpha01"** * **直接在UI觀察該函數,因為函數會emit值到liveData** ```kotlin= fun getBookListFromDatabase2() = liveData { database.getBookList() .onStart { Timber.d("getBook list flow start") } .catch { Timber.d("getBook list flow catch error") } .onCompletion { Timber.d("getBook list flow completion") selectLock = false } .collectLatest { emit(it) } } //在UI layer觀察 bookStoreViewModel.getBookListFromDatabase2().observe(this, Observer { newList -> newList?.let { adapter.data = it //要判斷是否為新增資料 在執行下載圖片,否則直接由快取顯示 apiBookViewModel.getImgFromUrl(it) } }) ``` C. * **轉換成asLiveData** * 方法跟liveData builder一樣,只是把liveData builder封裝成asLiveData ```kotlin= fun getBookListFromDatabase() = database.getBookList().flowOn(Dispatchers.IO) .onStart { Timber.d("getBook list flow start") } .catch { Timber.d("getBook list flow catch error") } .onCompletion { Timber.d("getBook list flow completion") selectLock = false }.asLiveData() //UI layer觀察 bookStoreViewModel.getBookListFromDatabase().observe(this, Observer { newList -> newList?.let { adapter.data = it //要判斷是否為新增資料 在執行下載圖片,否則直接由快取顯示 apiBookViewModel.getImgFromUrl(it) } }) ``` [參考資料] [知乎](http://zhuanlan.zhihu.com/p/312468040) [知乎](https://zhuanlan.zhihu.com/p/347785851) [gitconnected](https://levelup.gitconnected.com/learn-by-doing-live-data-builder-bridging-coroutines-and-live-data-in-android-6ea9aa597b4) ###### tags: `flow` `kotlin` `Android`