【譯】什麼是Flow?在Android項目中如何使用?

若是您是一位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是什麼?

Kotlin中的Flow API是能夠更好的異步處理按順序執行的數據流的方法。

在RxJava中,Observables類型是表示項目流結構的示例。 在訂閱者進行訂閱以前,其主體不會被執行。 訂閱後,訂閱者便開始獲取發射的數據項。 一樣,Flow在相同的條件下工做,即在流生成器內部的代碼到了收集流後纔開始運行。

開始在您的項目中集成Flow API

讓咱們建立一個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)
}
複製代碼

關於這裏:

  • 咱們將以500ms的延遲發出從0到10的數字。
  • 爲了發射數據,咱們將使用**emit()**收集發出的值。 它是FlowCollector的一部分,能夠用做接收器。
  • 最後,咱們使用flowOn運算符,這意味着應使用它來更改流發射的上下文。 在這裏,咱們可使用不一樣的Dispatcher,例如IO,Default等。

flowOn() 就如同 subscribeOn() 在 RxJava中同樣

第五步

如今,咱們須要編寫**setupClicks()**函數,在此咱們須要打印從流中發出的值。

private fun setupClicks() {
    button.setOnClickListener {
        CoroutineScope(Dispatchers.Main).launch {
            flow.collect {
                Log.d(TAG, it.toString())
            }
        }
    }
}
複製代碼

當咱們單擊按鈕時,咱們將一一打印這些值。

解釋一下:

  • flow.collect如今將開始從主線程上的流中提取/收集值。
  • 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」,而後開始發射。

假設咱們修改一下**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()-用於從一組給定的值建立流。 例如:
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的數據做爲流,並以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運算符.

Zip 運算符

若是您還記得上面的例子,咱們有兩個方法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)
            }
        }
    }
}
複製代碼

說明一下:

  • 單擊該按鈕時,將會開始執行。
  • 壓縮flowOne和flowTwo後會產生一對數據firstString和secondString,咱們將兩者鏈接起來。
  • 而後在Logcat中打印出來。 結果輸出將是:
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…

掘金:juejin.im/user/582d60…

Github: github.com/ditclear

相關文章
相關標籤/搜索