Kotlin Flow常見(jiàn)場(chǎng)景下的使用實(shí)例
Kotlin Flow在開(kāi)發(fā)中的常用場(chǎng)景使用
大家了解了 Flow 的創(chuàng)建與接收流程,了解 SharedFlow 創(chuàng)建的幾種方式,各個(gè)參數(shù)的用途,了解了SharedFlow的 "青春版" StateFlow
的創(chuàng)建與接收,已經(jīng)他們與 LiveData 的異同。
注:這里青春版打上引號(hào),只是調(diào)侃而已,并不是說(shuō) StateFlow 比 SharedFlow 更加輕量,而是StateFlow使用更加簡(jiǎn)單,更加的場(chǎng)景化而已,使用起來(lái)感覺(jué)比較青春版而已。
那么在真實(shí)的開(kāi)發(fā)環(huán)境中我們是如何使用Flow的呢?這里從幾點(diǎn)舉例說(shuō)明一下。
一、網(wǎng)絡(luò)請(qǐng)求搭載Retrofit
之前在網(wǎng)上看到有人提問(wèn),為什么Retrofit不能返回 Flow 這樣的對(duì)象。使用一個(gè) FlowCallAdapterFactory 那我就可以直接使用Flow來(lái)傳遞了。
不是不行,有第三方的依賴(lài)實(shí)現(xiàn)了此功能,為什么官方不出,其實(shí)官方已經(jīng)給出了建議。
如果我想使用flow來(lái)傳遞數(shù)據(jù),有哪些方式返回Flow的方式呢?這里有幾種方案
1.1 LiveDataCallAdapterFactory
Retrofit 增加了 LiveDataCallAdapterFactory,我們可以使用LiveData來(lái)包裹對(duì)象
interface NewsApi { @POST("/wanandroid") fun fetchNewsLiveData( @FieldMap map:Map<String,String> ):LiveData<ApiResponse<NewsBean>> }
使用的時(shí)候
fetchNewsLiveData().asFlow()
這樣不就轉(zhuǎn)成了Flow了嗎?如果想轉(zhuǎn)為StateFlow 或者SharedFlow,可以繼續(xù)shareIn stateIn 之類(lèi)的方法轉(zhuǎn)換為熱流。
1.2 suspend
使用掛起函數(shù)直接返回對(duì)象,然后使用flow函數(shù)創(chuàng)建出Flow對(duì)象,也是非常的簡(jiǎn)單,這也是官方推薦的方式。
interface NewsApi { @POST("/wanandroid") suspend fun fetchNews( @FieldMap map:Map<String,String> ):ApiResponse<NewsBean> }
使用的時(shí)候,直接就創(chuàng)建了一個(gè)flow對(duì)象
flow { emit(fetchNews()) }
如果想轉(zhuǎn)為StateFlow 或者SharedFlow,可以繼續(xù)shareIn stateIn 之類(lèi)的方法轉(zhuǎn)換為熱流。
這種網(wǎng)絡(luò)數(shù)據(jù)使用Flow的方式,好處是可以很方便的進(jìn)行合并,合流,展平等操作,很方便的使用操作符轉(zhuǎn)換成我們想要的數(shù)據(jù)。
二、協(xié)程與Flow的選擇與差異
協(xié)程與Flow的選擇,什么情況下我應(yīng)該使用協(xié)程請(qǐng)求網(wǎng)絡(luò),什么情況下我才使用Flow 來(lái)操作UI。
其實(shí)我們對(duì)于實(shí)時(shí)性不高的數(shù)據(jù),我們可以使用 Kotlin 協(xié)程處理,而對(duì)于實(shí)時(shí)性較高的數(shù)據(jù),我們可以用 Flow 來(lái)處理。
例如動(dòng)態(tài)詳情頂部是詳情數(shù)據(jù)固定的數(shù)據(jù),而底部是列表和點(diǎn)贊評(píng)論的數(shù)量,這些是動(dòng)態(tài)的數(shù)據(jù),那么我們?cè)夙敳烤涂梢杂脜f(xié)程請(qǐng)求,在底部我們使用Flow處理數(shù)據(jù)再通知其改變。
@POST("/wanandroid") suspend fun fetchNews( @FieldMap map: Map<String, String> ): BaseBean<NewsBean>
suspend fun fetchNewsDetail(): OkResult<NewsBean> { return extRequestHttp { DemoRetrofit.apiService.fetchNews( mapOf("id" to "12232", "key" to "2") ) } }
lifecycleScope.launch { val detail = mViewModel.mRepository.fetchNewsDetail() detail.checkSuccess { updateUI(it) } } private fun updateUI(newsBean: NewsBean?) { // XXX }
而下面的列表與動(dòng)態(tài)點(diǎn)贊分享數(shù)據(jù),我們可以使用 Flow 來(lái)操作,當(dāng)點(diǎn)贊或轉(zhuǎn)發(fā)數(shù)發(fā)生變化時(shí),updateUI() 會(huì)被執(zhí)行,UI根據(jù)最新的數(shù)據(jù)更新。
private val _stateFlow = MutableStateFlow("") val stateFlow: StateFlow<String> = _searchFlow fun changeState() { viewModelScope.launch { val detail = mRepository.changeState() detail.checkSuccess { //進(jìn)一系列的數(shù)據(jù)合流 //進(jìn)行一系列的排序、轉(zhuǎn)換之后設(shè)置給Flow _stateFlow.value = it ?: "" } } }
操作UI的偽代碼如下:
private fun changeData() { mViewModel.changeState() } private fun updateUI() { //更新一些UI } override fun startObserve() { lifecycleScope.launchWhenCreated { mViewModel.stateFlow.collect { updateUI() } } }
是不是靜態(tài)的頁(yè)面不能用 Flow ,能不能用 LiveData ? 當(dāng)然可以用了,上面的只是推薦使用,其他的方式當(dāng)然都可以例如:
fun getNewsDetail(): LiveData<NewsBean?> { return liveData { val detail = mRepository.fetchNewsDetail() if (detail is OkResult.Success) { emit(detail.data) } else { emit(null) } } }
使用的時(shí)候:
fun getData(){ mViewModel.getNewsDetail().observe(this) { updateUI() } } private fun updateUI() { //更新一些UI }
三、StateFlow與SharedFlow的選擇
什么時(shí)候使用StateFlow ,什么時(shí)候使用 SharedFlow ,在之前 SharedFlow 的文章中,我們對(duì)比過(guò) StateFlow,SharedFlow,LiveData 的區(qū)別。
關(guān)于 SharedFlow、StateFlow、LiveData的對(duì)比,個(gè)人的結(jié)論是:根據(jù)不同的場(chǎng)景 LiveData StateFlow SharedFlow 都有自己特定的使用場(chǎng)景,誰(shuí)也無(wú)法真的完全平替誰(shuí)。誰(shuí)也不是誰(shuí)的超集,都是各有利弊,按需選擇即可。這里不過(guò)多贅述。
那其實(shí)從另一角度,我們區(qū)別不同的場(chǎng)景為狀態(tài)和事件,看此場(chǎng)景是狀態(tài)驅(qū)動(dòng)還是事件驅(qū)動(dòng)的。
比如我現(xiàn)在點(diǎn)擊了按鈕,需要彈窗了,然后使用StateFlow來(lái)記錄狀態(tài),然后收集到這個(gè)事件彈出彈框了,然后我們關(guān)閉彈窗去瀏覽此頁(yè)面的其他信息了了,但是當(dāng)我們旋轉(zhuǎn)手機(jī)屏幕之后,我們會(huì)發(fā)現(xiàn)彈窗又出來(lái)了。這就不合理了。
有同學(xué)說(shuō),這是StateFlow的問(wèn)題,此情況我們需要使用LiveData,那LiveData就沒(méi)有問(wèn)題了嗎?
我們測(cè)試一下:
@HiltViewModel class Demo4ViewModel @Inject constructor( val mRepository: Demo5Repository, val savedState: SavedStateHandle ) : BaseViewModel() { val channel = Channel<String>(Channel.CONFLATED) private val _searchLD = MutableLiveData<String>() val searchLD: LiveData<String> = _searchLD private val _searchFlow = MutableStateFlow("") val searchFlow: StateFlow<String> = _searchFlow private val _sharedFlow = MutableSharedFlow<String>(replay = 1, onBufferOverflow = BufferOverflow.SUSPEND) val sharedFlow: SharedFlow<String> = _sharedFlow fun changeSearch(keyword: String) { _sharedFlow.tryEmit(keyword) _searchFlow.value = keyword _searchLD.value = keyword channel.trySend(keyword) } }
我們測(cè)試 LiveData Channel StateFlow SharedFlow(replay=1)
點(diǎn)擊按鈕發(fā)送事件
旋轉(zhuǎn)屏幕查看Log-3個(gè)數(shù)據(jù)
除了Channel,原來(lái)你們都會(huì)再次觸發(fā),別急我們修改SharedFlow(replay =0)
旋轉(zhuǎn)屏幕查看Log-2個(gè)數(shù)據(jù)
SharedFlow就不會(huì)再觸發(fā)了。
到這里,StateFlow 與 SharedFlow 的使用場(chǎng)景就應(yīng)該很清晰了,狀態(tài)(State)用 StateFlow ;事件(Event)用 SharedFlow
關(guān)于SateFlow SharedFlow LiveData 的對(duì)比可以看這里。
總結(jié)
Flow 的使用總的來(lái)說(shuō)還是很廣泛,如果你的項(xiàng)目是Kotlin語(yǔ)言開(kāi)發(fā)的,強(qiáng)烈建議使用Flow。
關(guān)于LiveData 替換為Flow的問(wèn)題,這幾篇文章也給出了答案,看不同的場(chǎng)景,SateFlow SharedFlow LiveData 各有優(yōu)缺點(diǎn),無(wú)法真的說(shuō)誰(shuí)能真的完全平替誰(shuí)。
以上就是Kotlin Flow常見(jiàn)場(chǎng)景下的使用實(shí)例的詳細(xì)內(nèi)容,更多關(guān)于Kotlin Flow使用場(chǎng)景的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Kotlin協(xié)程之Flow基礎(chǔ)原理示例解析
- Kotlin Flow封裝類(lèi)SharedFlow StateFlow LiveData使用對(duì)比
- Kotlin Flow常用封裝類(lèi)StateFlow使用詳解
- Kotlin Flow操作符及基本使用詳解
- Kotlin + Flow 實(shí)現(xiàn)Android 應(yīng)用初始化任務(wù)啟動(dòng)庫(kù)
- Android使用Kotlin和RxJava 2.×實(shí)現(xiàn)短信驗(yàn)證碼倒計(jì)時(shí)效果
- Kotlin使用flow實(shí)現(xiàn)倒計(jì)時(shí)功能(示例詳解)
相關(guān)文章
Android調(diào)用相機(jī)并將照片存儲(chǔ)到sd卡上實(shí)現(xiàn)方法
Android中實(shí)現(xiàn)拍照有兩種方法,一種是調(diào)用系統(tǒng)自帶的相機(jī),還有一種是自己用Camera類(lèi)和其他相關(guān)類(lèi)實(shí)現(xiàn)相機(jī)功能,這種方法定制度比較高,需要的朋友可以了解下2012-12-12簡(jiǎn)單實(shí)現(xiàn)Android滾動(dòng)公告欄
這篇文章主要為大家詳細(xì)介紹了如何簡(jiǎn)單實(shí)現(xiàn)Android滾動(dòng)公告欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01TextInputLayout輸入框控件的懸浮標(biāo)簽
這篇文章主要為大家詳細(xì)介紹了TextInputLayout輸入框控件的懸浮標(biāo)簽,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Android實(shí)戰(zhàn)教程第四十篇之Chronometer實(shí)現(xiàn)倒計(jì)時(shí)
這篇文章主要介紹了Android實(shí)戰(zhàn)教程第四十篇之Chronometer實(shí)現(xiàn)倒計(jì)時(shí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Android實(shí)現(xiàn)錄音方法(仿微信語(yǔ)音、麥克風(fēng)錄音、發(fā)送語(yǔ)音、解決5.0以上BUG)
大家平時(shí)在使用微信qq聊天時(shí)經(jīng)常會(huì)發(fā)送語(yǔ)音功能,今天小編給大家?guī)?lái)了基于android實(shí)現(xiàn)錄音的方法仿微信語(yǔ)音、麥克風(fēng)錄音、發(fā)送語(yǔ)音、解決5.0以上BUG,需要的朋友參考下吧2018-04-04Android實(shí)現(xiàn)簡(jiǎn)單點(diǎn)贊動(dòng)畫(huà)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單點(diǎn)贊動(dòng)畫(huà),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08非常詳細(xì)的android so庫(kù)逆向調(diào)試教程
這篇文章主要給大家介紹了關(guān)于android so庫(kù)逆向調(diào)試的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-08-08Android編程基礎(chǔ)之簡(jiǎn)單Button事件響應(yīng)綜合提示控件Toast應(yīng)用示例
這篇文章主要介紹了Android編程基礎(chǔ)之簡(jiǎn)單Button事件響應(yīng)綜合提示控件Toast應(yīng)用,結(jié)合實(shí)例形式分析了Button事件響應(yīng)與Toast提醒的相關(guān)操作技巧,需要的朋友可以參考下2016-10-10