Android SharedFlow详解
轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/zhaoyanjun6/article/details/121911675
本文出自【趙彥軍的博客】
文章目錄
- 系列文章
- 什么是SharedFlow
- 實戰(zhàn)
- 默認(rèn)無粘性
- replay 代表重放的數(shù)據(jù)個數(shù)
- extraBufferCapacity 額外的數(shù)據(jù)緩存池
- onBufferOverflow
- 什么情況下用 SharedFlow
- tryEmit
- 將冷流轉(zhuǎn)化為SharedFlow
- 總結(jié)
系列文章
Android SharedFlow詳解
Android StateFlow詳解
什么是SharedFlow
和 StateFlow 一樣,SharedFlow 也是熱流,它可以將已發(fā)送過的數(shù)據(jù)發(fā)送給新的訂閱者,并且具有高的配置性。SharedFlow 是一個接口,繼承 Flow
在使用是,一般使用 MutableSharedFlow
SharedFlow 有如下特點:
1、是熱數(shù)據(jù)流 ,及時沒有接收者,也會發(fā)射數(shù)據(jù)
2、SharedFlow 是 StateFlow 的可配置性極高的泛化數(shù)據(jù)流。
3、可以有多個接收器,一個數(shù)據(jù)可以被多個接收
實戰(zhàn)
class MainActivity : AppCompatActivity() {private val mutableSharedFlow = MutableSharedFlow<String>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)val binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)lifecycleScope.launch {mutableSharedFlow.collect {Log.d("bus-", "觀察者1,$it")}mutableSharedFlow.collect {Log.d("bus-", "觀察者2,$it")}}//發(fā)射數(shù)據(jù)lifecycleScope.launch {mutableSharedFlow.emit(System.currentTimeMillis().toString())}} }日志:
D/bus-: 觀察者1,1639392387467很奇怪,觀察者2 沒有輸出日志。我們的期望是 發(fā)射一個數(shù)據(jù),可以被兩個觀察者接收,但實際只有一個觀察者接收了數(shù)據(jù)。
事實上 第二個 觀察者的代碼就沒有執(zhí)行。也就是 下面這段代碼 沒有被執(zhí)行。
mutableSharedFlow.collect {Log.d("bus-", "觀察者2,$it") }collect 是掛起函數(shù),因為他可以不斷的接收值,會不斷的掛起,不斷的恢復(fù)。具體實現(xiàn)在 SharedFlowImpl 中。
可以這么寫,用兩個協(xié)程去接收值:
class MainActivity : AppCompatActivity() {private val mutableSharedFlow = MutableSharedFlow<String>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)val binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)lifecycleScope.launch {mutableSharedFlow.collect {Log.d("bus-", "觀察者1,$it")}}lifecycleScope.launch {mutableSharedFlow.collect {Log.d("bus-", "觀察者2,$it")}}//發(fā)射數(shù)據(jù)lifecycleScope.launch {mutableSharedFlow.emit(System.currentTimeMillis().toString())}} }日志輸出:
D/bus-: 觀察者1,1639393316855 D/bus-: 觀察者2,1639393316855默認(rèn)無粘性
SharedFlow 默認(rèn)無粘性的,也就是后面的觀察者不能收到前面已經(jīng)發(fā)射的數(shù)據(jù)。
當(dāng)然也有api,支持。
replay 代表重放的數(shù)據(jù)個數(shù)
replay 為0 代表不重放,也就是沒有粘性
replay 為1 代表重放最新的一個數(shù)據(jù),后來的接收器能接受1個最新數(shù)據(jù)。
replay 為2 代表重放最新的兩個數(shù)據(jù),后來的接收器能接受2個最新數(shù)據(jù)。
示例如下:
class MainActivity : AppCompatActivity() {private val mutableSharedFlow = MutableSharedFlow<String>(replay = 2)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)val binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)lifecycleScope.launch {mutableSharedFlow.collect {Log.d("bus-", "觀察者1,$it")}}lifecycleScope.launch {mutableSharedFlow.collect {Log.d("bus-", "觀察者2,$it")}}//發(fā)射數(shù)據(jù)lifecycleScope.launch {mutableSharedFlow.emit("a")mutableSharedFlow.emit("b")mutableSharedFlow.emit("c")}lifecycleScope.launch {delay(2000)mutableSharedFlow.collect {Log.d("bus-", "觀察者3,$it")}}} }輸出日志
D/bus-: 觀察者1,a D/bus-: 觀察者1,b D/bus-: 觀察者2,a D/bus-: 觀察者2,b D/bus-: 觀察者2,c D/bus-: 觀察者1,c D/bus-: 觀察者3,b D/bus-: 觀察者3,c觀察者1 ,觀察者2 都接受到了三個數(shù)據(jù),分別是 a、b、c
觀察者3 是后來加入的,可以接收到最新的兩個數(shù)據(jù) b、c
extraBufferCapacity 額外的數(shù)據(jù)緩存池
Flow 存在發(fā)送過快,消費太慢的情況,這種情況下,就需要使用緩存池,把未消費的數(shù)據(jù)存下來。
緩沖池容量 = replay + extraBufferCapacity
如果總量為 0 ,就 Int.MAX_VALUE
onBufferOverflow
如果指定了有限的緩存容量,那么超過容量以后怎么辦?
- BufferOverflow.SUSPEND : 超過就掛起,默認(rèn)實現(xiàn)
- BufferOverflow.DROP_OLDEST : 丟棄最老的數(shù)據(jù)
- BufferOverflow.DROP_LATEST : 丟棄最新的數(shù)據(jù)
什么情況下用 SharedFlow
當(dāng)你有如下場景時,需要使用 SharedFlow:
- 發(fā)生訂閱時,需要將過去已經(jīng)更新的 n 個值,同步給新的訂閱者。
- 配置緩存策略。
- 有多個訂閱者。
tryEmit
當(dāng) MutableSharedFlow 中緩存數(shù)據(jù)量超過閾值時,emit方法和 tryEmit方法的處理方式會有不同:
- emit方法:當(dāng)緩存策略為 BufferOverflow.SUSPEND 時,emit方法會掛起,直到有新的緩存空間。
- tryEmit 方法:tryEmit 會返回一個 Boolean 值,true 代表傳遞成功,false 代表會產(chǎn)生一個回調(diào),讓這次數(shù)據(jù)發(fā)射掛起,直到有新的緩存空間。
將冷流轉(zhuǎn)化為SharedFlow
直接使用官網(wǎng)的代碼,方法是使用 Flow 的擴(kuò)展方法 shareIn:
class NewsRemoteDataSource(...,private val externalScope: CoroutineScope, ) {val latestNews: Flow<List<ArticleHeadline>> = flow {...}.shareIn(externalScope,replay = 1,started = SharingStarted.WhileSubscribed() // 啟動政策) }重點是參數(shù)三,分別提供了三個啟動策略:
- SharingStarted.WhileSubscribed():存在訂閱者時,將使上游提供方保持活躍狀態(tài)。
- SharingStarted.Eagerly:立即啟動提供方。
- SharingStarted.Lazily:在第一個訂閱者出現(xiàn)后開始共享數(shù)據(jù),并使數(shù)據(jù)流永遠(yuǎn)保持活躍狀態(tài)。
總結(jié)
Flow 給我的感覺就像古老的印刷術(shù),版面定了就不可更改,不過,該版面可印刷多張內(nèi)容;StateFlow 給我的感覺就像活字印刷,可以不停的更改版面,也可以使用同一個版面印刷很多內(nèi)容。
如果你要使用Flow 記錄數(shù)據(jù)的狀態(tài),StateFlow 和 SharedFlow 會是一個不錯的選擇。StateFlow 和 SharedFlow 提供了在 Flow 中使用 LiveData式更新數(shù)據(jù)的能力,但是如果要在UI 層使用,需要注意生命周期的問題。
StateFlow 和 SharedFlow 相比,StateFlow 需要提供初始值,SharedFlow 配置靈活,可提供舊數(shù)據(jù)同步和緩存配置的功能。
總結(jié)
以上是生活随笔為你收集整理的Android SharedFlow详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OkHttp ResponseBody没
- 下一篇: Android StateFlow详解