亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Kotlin Flow常見場景下的使用實例

 更新時間:2022年08月31日 14:55:41   作者:newki  
這篇文章主要為大家介紹了Kotlin Flow常見場景下的使用實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

Kotlin Flow在開發(fā)中的常用場景使用

大家了解了 Flow 的創(chuàng)建與接收流程,了解 SharedFlow 創(chuàng)建的幾種方式,各個參數(shù)的用途,了解了SharedFlow的 "青春版" StateFlow 的創(chuàng)建與接收,已經(jīng)他們與 LiveData 的異同。

注:這里青春版打上引號,只是調(diào)侃而已,并不是說 StateFlow 比 SharedFlow 更加輕量,而是StateFlow使用更加簡單,更加的場景化而已,使用起來感覺比較青春版而已。

那么在真實的開發(fā)環(huán)境中我們是如何使用Flow的呢?這里從幾點舉例說明一下。

一、網(wǎng)絡(luò)請求搭載Retrofit

之前在網(wǎng)上看到有人提問,為什么Retrofit不能返回 Flow 這樣的對象。使用一個 FlowCallAdapterFactory 那我就可以直接使用Flow來傳遞了。

不是不行,有第三方的依賴實現(xiàn)了此功能,為什么官方不出,其實官方已經(jīng)給出了建議。

如果我想使用flow來傳遞數(shù)據(jù),有哪些方式返回Flow的方式呢?這里有幾種方案

1.1 LiveDataCallAdapterFactory

Retrofit 增加了 LiveDataCallAdapterFactory,我們可以使用LiveData來包裹對象

interface NewsApi {
    @POST("/wanandroid")
    fun fetchNewsLiveData(
        @FieldMap map:Map<String,String>
    ):LiveData<ApiResponse<NewsBean>>
}

使用的時候

fetchNewsLiveData().asFlow()

這樣不就轉(zhuǎn)成了Flow了嗎?如果想轉(zhuǎn)為StateFlow 或者SharedFlow,可以繼續(xù)shareIn stateIn 之類的方法轉(zhuǎn)換為熱流。

1.2 suspend

使用掛起函數(shù)直接返回對象,然后使用flow函數(shù)創(chuàng)建出Flow對象,也是非常的簡單,這也是官方推薦的方式。

interface NewsApi {
    @POST("/wanandroid")
   suspend  fun fetchNews(
        @FieldMap map:Map<String,String>
    ):ApiResponse<NewsBean>
}

使用的時候,直接就創(chuàng)建了一個flow對象

flow {
  emit(fetchNews())
}

如果想轉(zhuǎn)為StateFlow 或者SharedFlow,可以繼續(xù)shareIn stateIn 之類的方法轉(zhuǎn)換為熱流。

這種網(wǎng)絡(luò)數(shù)據(jù)使用Flow的方式,好處是可以很方便的進行合并,合流,展平等操作,很方便的使用操作符轉(zhuǎn)換成我們想要的數(shù)據(jù)。

二、協(xié)程與Flow的選擇與差異

協(xié)程與Flow的選擇,什么情況下我應(yīng)該使用協(xié)程請求網(wǎng)絡(luò),什么情況下我才使用Flow 來操作UI。

其實我們對于實時性不高的數(shù)據(jù),我們可以使用 Kotlin 協(xié)程處理,而對于實時性較高的數(shù)據(jù),我們可以用 Flow 來處理。

例如動態(tài)詳情頂部是詳情數(shù)據(jù)固定的數(shù)據(jù),而底部是列表和點贊評論的數(shù)量,這些是動態(tài)的數(shù)據(jù),那么我們再頂部就可以用協(xié)程請求,在底部我們使用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
    }

而下面的列表與動態(tài)點贊分享數(shù)據(jù),我們可以使用 Flow 來操作,當(dāng)點贊或轉(zhuǎn)發(fā)數(shù)發(fā)生變化時,updateUI() 會被執(zhí)行,UI根據(jù)最新的數(shù)據(jù)更新。

    private val _stateFlow = MutableStateFlow("")
    val stateFlow: StateFlow<String> = _searchFlow
    fun changeState() {
        viewModelScope.launch {
            val detail = mRepository.changeState()
            detail.checkSuccess {
                //進一系列的數(shù)據(jù)合流
                //進行一系列的排序、轉(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)的頁面不能用 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)
            }
        }
    }

使用的時候:

    fun getData(){
        mViewModel.getNewsDetail().observe(this) {
            updateUI()
        }
    }
    private fun updateUI() {
        //更新一些UI
    }

三、StateFlow與SharedFlow的選擇

什么時候使用StateFlow ,什么時候使用 SharedFlow ,在之前 SharedFlow 的文章中,我們對比過 StateFlow,SharedFlow,LiveData 的區(qū)別。

關(guān)于 SharedFlow、StateFlow、LiveData的對比,個人的結(jié)論是:根據(jù)不同的場景 LiveData StateFlow SharedFlow 都有自己特定的使用場景,誰也無法真的完全平替誰。誰也不是誰的超集,都是各有利弊,按需選擇即可。這里不過多贅述。

那其實從另一角度,我們區(qū)別不同的場景為狀態(tài)和事件,看此場景是狀態(tài)驅(qū)動還是事件驅(qū)動的。

比如我現(xiàn)在點擊了按鈕,需要彈窗了,然后使用StateFlow來記錄狀態(tài),然后收集到這個事件彈出彈框了,然后我們關(guān)閉彈窗去瀏覽此頁面的其他信息了了,但是當(dāng)我們旋轉(zhuǎn)手機屏幕之后,我們會發(fā)現(xiàn)彈窗又出來了。這就不合理了。

有同學(xué)說,這是StateFlow的問題,此情況我們需要使用LiveData,那LiveData就沒有問題了嗎?

我們測試一下:

@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)
    }
}

我們測試 LiveData Channel StateFlow SharedFlow(replay=1)

點擊按鈕發(fā)送事件

旋轉(zhuǎn)屏幕查看Log-3個數(shù)據(jù)

除了Channel,原來你們都會再次觸發(fā),別急我們修改SharedFlow(replay =0)

旋轉(zhuǎn)屏幕查看Log-2個數(shù)據(jù)

SharedFlow就不會再觸發(fā)了。

到這里,StateFlow 與 SharedFlow 的使用場景就應(yīng)該很清晰了,狀態(tài)(State)用 StateFlow ;事件(Event)用 SharedFlow

關(guān)于SateFlow SharedFlow LiveData 的對比可以看這里。

總結(jié)

Flow 的使用總的來說還是很廣泛,如果你的項目是Kotlin語言開發(fā)的,強烈建議使用Flow。

關(guān)于LiveData 替換為Flow的問題,這幾篇文章也給出了答案,看不同的場景,SateFlow SharedFlow LiveData 各有優(yōu)缺點,無法真的說誰能真的完全平替誰。

以上就是Kotlin Flow常見場景下的使用實例的詳細內(nèi)容,更多關(guān)于Kotlin Flow使用場景的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論