day23 stateFlow状态流,又是没梗的一天

前面我们讲到如何应coroutine的flow和liveData合作,但android其实还推出了另一个东西,stateFlow,刚好之前的line截图,也点出了这个主题

为什麽说stateFlow是冲着liveData来的呢?

其实有去看文档的范例就会知道,用法跟liveData超级像,连那个封装方法都如出一辙,让你觉得是不是想换个包装骗我

不如~写个范例试试

只看文档范例的确很像,但~还是要试过才会知道的吧

//viewModel
private val _postStateFlow = MutableStateFlow(Post(0,0,"",""))
val postStateFlow = _postStateFlow

init {
    viewModelScope.launch {
        repo.postFlow.collect {
            _postStateFlow.value = it
        }
    }
}
//fragment
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED){
        viewModel.postStateFlow.collect {
            Timber.d(it.toString())
        }
    }
}

等等,除了用到corouitne以外,这不就liveData,而且比昨天的asLiveData写起来还要长

没事,我们先来简化一下

//viewModel
var stateInFlow: StateFlow<Post> =
    repo.postFlow.stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(),
        Post(0, 0, "", "")
    )

Tip for Android apps! You can use WhileSubscribed(5000) most of the time to keep the upstream flow active for 5 seconds more after the disappearance of the last collector. That avoids restarting the upstream flow in certain situations such as configuration changes. This tip is especially helpful when upstream flows are expensive to create and when these operators are used in ViewModels.

我翻一下,就是在某些case里面,如萤幕旋转,可能会有一小段时间没有订阅者,所以用 WhileSubscribed(时间)来定义没订阅者後几秒才停止,尤其是在producer的操作消耗较多资源,且这些操作在viewModel执行的时候。

stateFlow的特性

stateFlow必须设置初始值,所以每个订阅者至少能收到一个值,如果不想对此作设置,可以透过将类别改成nullable,去做判定,或是在seal class新增一个空的状态

stateFlow的updateState内部会检查,如旧值和新值一样,就不会更新

replay被强制设为1,这代表新的订阅者会立刻收到最新的状态

可以透过values能到单个最新值,而不是collect整个流

和ShareFlow一样的地方

作为hotflow他不会自己停下,除非有特别设置(stateFlow继承自shareFlow)

对的,这里默默地多了一个东西SharingStarted

  1. SharingStarted.Eagerly - 立刻开始且不会停止
  2. SharingStarted.Lazily - 从第一个观察者开始且不会停止
  3. SharingStarted.WhileSubscribed - 从第一个观察者开始,并在最後一个观察者消失时结束,保留快取
    https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/state-in.html

和sharedFlow相比

stateflow允许透过value同步访问最新的值,shareflow则否

interface StateFlow<out T> : SharedFlow<T> 

stateFlow是从sharedFlow改变出来的,stateFlow最後的发射值可背心添加的观察者观察到

在stateflow,不支援buffer,也不支援resetReplayCache,且必须有初始值.
当你需要对stateflow做出调整时,像是添加buffer,回朔多个值,省略初始值等等,可以用下列方式创建,范例为stateflow的基本实现,可根据需求做调整

// MutableStateFlow(initialValue) is a shared flow with the following parameters:
val shared = MutableSharedFlow(
    replay = 1,
    onBufferOverflow = BufferOverflow.DROP_OLDEST
)
shared.tryEmit(initialValue) // emit the initial value
val state = shared.distinctUntilChanged() // get StateFlow-like behavior

如果应用程序在後台,我们不需要总是监听位置更新。但是,我们需要缓存最後发出的项目,以便用户在获取当前位置时始终可以在屏幕上看到一些数据,即使是陈旧的数据。对於这种情况,我们可以使用stateIn运算符。

和liveData差别

相同

都只有唯一值
允许被多个观察者/订阅者 调用
永远提供观察者/订阅者 最新值,与 观察者/订阅者 数量无关
支持databinding

不同

必须设置初始值
方便切换thread

容易犯的错

不要用fun去创建stateFlow,这样会在每次呼叫viewModel.createStateFlow都创建一个新的实例

// DO NOT USE shareIn or stateIn in a function like this.
// It creates a new SharedFlow/StateFlow per invocation which is not reused!
fun createStateFlow() = 
    repo.postFlow.stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(),
        Post(0, 0, "", "")
    )

和flow相比,改变了什麽

floe是冷数据流,而stateFlow和sharedFlow是热数据流,他们的差别在於,flow在每次collect时,都会创建一个实例,而state和share在已经有实例的情况下,会观察同一个实例,所以他们可以收到同一个值

白话一点就是,他们会把流的值,给多个观察者,flow不行

Cold flows are created on-demand and emit data when they’re being observed. Hot flows are always active and can emit data regardless of whether or not they’re being observed.

作用

distinctUntilChanged - 回传一个流,且会过滤和前一个相同的值,主要用於提高性能,且在没有订阅者时,保留一个旧值

A state flow is a hot flow because its active instance exists independently of the presence of collectors. Its current value can be retrieved via the value property.
stateFlow作为热流,因为他的实例可以独立於collecter而存在,同时他也可以透过value,取值或设值

State flow never completes. A call to Flow.collect on a state flow never completes normally, and neither does a coroutine started by the Flow.launchIn function.
更重要的是,stateFlow永远不会结束,flow.collect永远不会正常的结束,所以务必要用repeatOnLifecycle来确保稳定性。
launchin也无法正常运作

在mutableStateflow vlaue的更新总是透过conflate,意即在大量操作的情况下,中间一部份的值会丢失,但总是能确保获取最新的值

stateFlow继承自shareFlow,特色是指存一个值,可用来推播体验,或是身分认证

连结

必看

文档
state-in

选看

jast


<<:  学习JavaScript第四天--字串型别、「赋值运算子+=、-=」「a++」「a--」

>>:  [Day 24] 动态元件v-bind:is

[Day 5] Vue的数据与方法

昨天简单介绍了Vue的 响应式,关於响应式的基本介绍可以直接看昨天那篇,这边就不再赘述(╹ڡ╹ )。...

MyBatis 设定

MyBatis设定 ...

Day16 X Polyfill-less Bundling Script & File Compression

今天是 Build Optimizations 主题的最後一篇了,到目前为止我们已经认识了 Cod...

简报版-第六章-谈谈手机APP下载安全吗?

其实原本最初规画想要做Index方式的纪录,然後多增加一些没写到的面向 不过,总是计画赶不上变化 ...

给客户提供优质服务并验证服务,让客户感觉有被重视

服务&验证 今日会直接讲解readinessProbe的部分,以及稍微提到Service这项...