
如果您是一位Android開發(fā)者,并且希望異步構建應用程序,則可能會使用到RxJava,因為RxJava具有可用于幾乎所有操作的運算符,并已成為Android中最重要的知識之一。
但是,有了Kotlin,很多人開始傾向于使用協(xié)程。 在Kotlin Coroutine 1.2.0 alpha版本中,Jetbrains附帶了Flow API。 現(xiàn)在,借助Kotlin中的Flow API,您可以處理按順序發(fā)出的數(shù)據流。
In Kotlin, Coroutine is just the scheduler part of RxJava but now with Flow APIs coming along side it, it can be alternative to RxJava in Android.
大意就是Flow結合協(xié)程可以代替Rxjava在Android中的地位。
在此博客中,我們將了解Flow API如何在Kotlin中工作以及如何在我們的android項目中使用它。本文將涵蓋以下主題:
Kotlin協(xié)程中的Flow API是什么?
開始在您的項目中集成Flow API
流構建器
一些有使用Flow 操作符的例子
讓我們一一討論。
Kotlin協(xié)程中的Flow API是什么?
Kotlin中的Flow API是可以更好的異步處理按順序執(zhí)行的數(shù)據流的方法。
在RxJava中,Observables類型是表示項目流結構的示例。 在訂閱者進行訂閱之前,其主體不會被執(zhí)行。 訂閱后,訂閱者便開始獲取發(fā)射的數(shù)據項。 同樣,F(xiàn)low在相同的條件下工作,即在流生成器內部的代碼到了收集流后才開始運行。
開始在您的項目中集成Flow API
讓我們創(chuàng)建一個android項目,然后集成Kotlin Flow API。
第一步
在應用程序的build.gradle中添加以下內容
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
接著在項目里的 build.gradle中添加
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
第二步
在MainActivity的布局文件中,我們創(chuàng)建一個具有按鈕的UI頁面。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
android:text="Launch Kotlin Flow"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
第三步
現(xiàn)在,讓我們開始在MainActivity中實現(xiàn)Flow API。 在Activity的onCreate()函數(shù)中,我們可以添加兩個函數(shù),例如:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupFlow()
setupClicks()
}
我們將聲明一個Int類型的Flow的lateinit變量:
lateinit var flow: Flow<Int>
第四步
在setupFlow()中編寫代碼,實現(xiàn)每延遲500毫秒后發(fā)出數(shù)據項。
fun setupFlow(){
flow = flow {
Log.d(TAG, "Start flow")
(0..10).forEach {
// Emit items with 500 milliseconds delay
delay(500)
Log.d(TAG, "Emitting $it")
emit(it)
}
}.flowOn(Dispatchers.Default)
}
關于這里:
- 我們將以500ms的延遲發(fā)出從0到10的數(shù)字。
- 為了發(fā)射數(shù)據,我們將使用emit()收集發(fā)出的值。 它是
FlowCollector的一部分,可以用作接收器。 - 最后,我們使用flowOn運算符,這意味著應使用它來更改流發(fā)射的上下文。 在這里,我們可以使用不同的Dispatcher,例如IO,Default等。
flowOn() 就如同 subscribeOn() 在 RxJava中一樣
第五步
現(xiàn)在,我們需要編寫setupClicks()函數(shù),在此我們需要打印從流中發(fā)出的值。
private fun setupClicks() {
button.setOnClickListener {
CoroutineScope(Dispatchers.Main).launch {
flow.collect {
Log.d(TAG, it.toString())
}
}
}
}
當我們單擊按鈕時,我們將一一打印這些值。
解釋一下:
- flow.collect現(xiàn)在將開始從主線程上的流中提取/收集值。
- UI會看起來像這樣:

- 輸出如下:
D/MainActivity: Start flow
D/MainActivity: Emitting 0
D/MainActivity: 0
D/MainActivity: Emitting 1
D/MainActivity: 1
D/MainActivity: Emitting 2
D/MainActivity: 2
D/MainActivity: Emitting 3
D/MainActivity: 3
D/MainActivity: Emitting 4
D/MainActivity: 4
D/MainActivity: Emitting 5
D/MainActivity: 5
D/MainActivity: Emitting 6
D/MainActivity: 6
D/MainActivity: Emitting 7
D/MainActivity: 7
D/MainActivity: Emitting 8
D/MainActivity: 8
D/MainActivity: Emitting 9
D/MainActivity: 9
D/MainActivity: Emitting 10
D/MainActivity: 10
如您所見,流只有在單擊按鈕時才開始,因為它會打印“Start Flow”,然后開始發(fā)射。
假設我們修改一下setupFlow()函數(shù)
private fun setupFlow() {
flow = flow {
Log.d(TAG, "Start flow")
(0..10).forEach {
// Emit items with 500 milliseconds delay
delay(500)
Log.d(TAG, "Emitting $it")
emit(it)
}
}.map {
it * it
}.flowOn(Dispatchers.Default)
}
在這里,您可以看到我們添加了map運算符,該運算符將獲取每個值并將其自身平方然后打印出來。
在flowOn上面編寫的所有內容都將在后臺線程中運行。
流構建器
流構建器不過就是構建流的方法。有4種方式:
- flowOf()-用于從一組給定的值創(chuàng)建流。 例如:
flowOf(4, 2, 5, 1, 7).onEach { delay(400) }.flowOn(Dispatcher.Default)
在這里,flowOf()取固定值,并每隔400毫秒后打印每個固定值。 當我們將收集器附加到流時,我們得到輸出:
D/MainActivity: 4
D/MainActivity: 2
D/MainActivity: 5
D/MainActivity: 1
D/MainActivity: 7
- asFlow()-這是一個擴展功能,有助于將類型轉換為流。 例如:
(1..5).asFlow().onEach{ delay(300)}.flowOn(Dispatchers.Default)
在這里,我們轉換范圍從1到5的數(shù)據作為流,并以300毫秒的延遲發(fā)射它們中的每一個。 當我們將收集器附加到流時,我們得到如下輸出:
D/MainActivity: 1
D/MainActivity: 2
D/MainActivity: 3
D/MainActivity: 4
D/MainActivity: 5
flow {}-該示例已在上面的Android示例中進行了說明。 這是一個構造函數(shù),用于構造任意流。
channelFlow {}-此構建器使用構建器本身提供的send與元素創(chuàng)建冷流。 例如:
channelFlow {
(0..10).forEach {
send(it)
}
}.flowOn(Dispatchers.Default)
輸出如下:
D/MainActivity: 0
D/MainActivity: 1
D/MainActivity: 2
D/MainActivity: 3
D/MainActivity: 4
D/MainActivity: 5
D/MainActivity: 6
D/MainActivity: 7
D/MainActivity: 8
D/MainActivity: 9
D/MainActivity: 10
最后,讓我們看看如何在項目中使用Flow運算符.
Zip 運算符
如果您還記得上面的例子,我們有兩個方法setupFlow()和setupClicks()。 我們將在MainActivity中修改這兩個函數(shù)。
首先,我們將聲明兩個Flow類型為String的lateinit變量,
lateinit var flowOne: Flow<String>
lateinit var flowTwo: Flow<String>
然后在setupFlow()中,將兩個流初始化為兩個變量.
private fun setupFlow() {
flowOne = flowOf("Himanshu", "Amit", "Janishar").flowOn(Dispatchers.Default)
flowTwo = flowOf("Singh", "Shekhar", "Ali").flowOn(Dispatchers.Default)
}
在setupClicks()中,我們將使用zip運算符來壓縮兩個流。
private fun setupClicks() {
button.setOnClickListener {
CoroutineScope(Dispatchers.Main).launch {
flowOne.zip(flowTwo)
{ firstString, secondString ->
"$firstString $secondString"
}.collect {
Log.d(TAG, it)
}
}
}
}
說明一下:
- 單擊該按鈕時,將會開始執(zhí)行。
- 壓縮flowOne和flowTwo后會產生一對數(shù)據firstString和secondString,我們將二者連接起來。
- 然后在Logcat中打印出來。 結果輸出將是:
D/MainActivity: Himanshu Singh
D/MainActivity: Amit Shekhar
D/MainActivity: Janishar Ali
注意:如果兩個流沒有相同的項目數(shù),則其中一個流完成后,該流將立即停止。
作者:Team MindOrks :)
原文鏈接:https://blog.mindorks.com/what-is-flow-in-kotlin-and-how-to-use-it-in-android-project
==================== 分割線 ======================
如果你想了解更多關于MVVM、Flutter、響應式編程方面的知識,歡迎關注我。
你可以在以下地方找到我:
簡書:http://www.itdecent.cn/u/117f1cf0c556
掘金:https://juejin.im/user/582d601d2e958a0069bbe687
Github: https://github.com/ditclear