若是您是一位Android開發者,而且但願異步構建應用程序,則可能會使用到RxJava,由於RxJava具備可用於幾乎全部操做的運算符,並已成爲Android中最重要的知識之一。php
可是,有了Kotlin,不少人開始傾向於使用協程。 在Kotlin Coroutine 1.2.0 alpha版本中,Jetbrains附帶了Flow API。 如今,藉助Kotlin中的Flow API,您能夠處理按順序發出的數據流。java
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.android
大意就是Flow結合協程能夠代替Rxjava在Android中的地位。git
在此博客中,咱們將瞭解Flow API如何在Kotlin中工做以及如何在咱們的android項目中使用它。本文將涵蓋如下主題:github
Kotlin協程中的Flow API是什麼?編程
開始在您的項目中集成Flow APIbash
流構建器app
一些有使用Flow 操做符的例子異步
本文會一一討論。ide
Kotlin中的Flow API是能夠更好的異步處理按順序執行的數據流的方法。
在RxJava中,Observables類型是表示項目流結構的示例。 在訂閱者進行訂閱以前,其主體不會被執行。 訂閱後,訂閱者便開始獲取發射的數據項。 一樣,Flow在相同的條件下工做,即在流生成器內部的代碼到了收集流後纔開始運行。
讓咱們建立一個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
的佈局文件中,咱們建立一個具備按鈕的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>
複製代碼
如今,讓咱們開始在MainActivity
中實現Flow API。 在Activity的onCreate()
函數中,咱們能夠添加兩個函數,例如:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupFlow()
setupClicks()
}
複製代碼
咱們將聲明一個Int類型的Flow的lateinit變量:
lateinit var flow: Flow<Int>
複製代碼
在setupFlow()
中編寫代碼,實現每延遲500毫秒後發出數據項。
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)
}
複製代碼
關於這裏:
FlowCollector
的一部分,能夠用做接收器。flowOn() 就如同 subscribeOn() 在 RxJava中同樣
如今,咱們須要編寫**setupClicks()**函數,在此咱們須要打印從流中發出的值。
private fun setupClicks() {
button.setOnClickListener {
CoroutineScope(Dispatchers.Main).launch {
flow.collect {
Log.d(TAG, it.toString())
}
}
}
}
複製代碼
當咱們單擊按鈕時,咱們將一一打印這些值。
解釋一下:
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」,而後開始發射。
假設咱們修改一下**setupFlow()**函數
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(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
複製代碼
(1..5).asFlow().onEach{ delay(300)}.flowOn(Dispatchers.Default)
複製代碼
在這裏,咱們轉換範圍從1到5的數據做爲流,並以300毫秒的延遲發射它們中的每個。 當咱們將收集器附加到流時,咱們獲得以下輸出:
D/MainActivity: 1
D/MainActivity: 2
D/MainActivity: 3
D/MainActivity: 4
D/MainActivity: 5
複製代碼
flow {}-該示例已在上面的Android示例中進行了說明。 這是一個構造函數,用於構造任意流。
channelFlow {}-此構建器使用構建器自己提供的send與元素建立冷流。 例如:
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運算符.
若是您還記得上面的例子,咱們有兩個方法setupFlow()
和setupClicks()
。 咱們將在MainActivity
中修改這兩個函數。
首先,咱們將聲明兩個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)
}
}
}
}
複製代碼
說明一下:
D/MainActivity: Himanshu Singh
D/MainActivity: Amit Shekhar
D/MainActivity: Janishar Ali
複製代碼
注意:若是兩個流沒有相同的項目數,則其中一個流完成後,該流將當即中止。
做者:Team MindOrks :)
原文連接:blog.mindorks.com/what-is-flo…
==================== 分割線 ======================
若是你想了解更多關於MVVM、Flutter、響應式編程方面的知識,歡迎關注我。
你能夠在如下地方找到我:
簡書:www.jianshu.com/u/117f1cf0c…
Github: github.com/ditclear