【译】什么是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

相关文章
相关标签/搜索