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