0
点赞
收藏
分享

微信扫一扫

【译】什么是Flow?在Android项目中如何使用?

如果您是一位Android开发者,并且希望异步构建应用程序,则可能会使用到RxJava,因为RxJava具有可用于几乎所有操作的运算符,并已成为Android中最重要的知识之一。

但是,有了Kotlin,很多人开始倾向于使用协程。 在Kotlin Coroutine 1.2.0 alpha版本中,Jetbrains附带了Flow API。 现在,借助Kotlin中的Flow API,您可以处理按顺序发出的数据流。

大意就是Flow结合协程可以代替Rxjava在Android中的地位。

在此博客中,我们将了解Flow API如何在Kotlin中工作以及如何在我们的android项目中使用它。本文将涵盖以下主题:

  • Kotlin协程中的Flow API是什么?

  • 开始在您的项目中集成Flow API

  • 流构建器

  • 一些有使用Flow 操作符的例子

让我们一一讨论。

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等。
第五步

现在,我们需要编写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

要查看项目,请单击此处

原文链接:https://blog.mindorks.com/what-is-flow-in-kotlin-and-how-to-use-it-in-android-project

==================== 分割线 ======================

如果你想了解更多关于MVVM、Flutter、响应式编程方面的知识,欢迎关注我。

你可以在以下地方找到我:

简书:https://www.jianshu.com/u/117f1cf0c556

掘金:https://juejin.im/user/582d601d2e958a0069bbe687

Github: https://github.com/ditclear

举报

相关推荐

0 条评论