前言
学过kotlin的同学知道,协程的挂起函数可以异步的返回单个值,但是该如何异步返回多个计算好的值呢,这就是Flow异步数据流的用武之地。但是Flow不仅仅于此,更形象的说,Flow是RxJava,kotlin版本的实现。
官方定义
我们可以从Android官网,Flow定义:在协程中,与仅返回单个值的挂起函数相反,数据流可按顺序发出多个值。例如,我们可以通过数据流从数据库中实时接收更新。数据流使用挂起函数通过异步方式生成和使用值,也就是说,数据流可安全地发出网络请求以生成下一个值,而不会阻塞主线程。
开始使用
概念都是晦涩难懂的,我们直接看个简单例子:
首先我们gradle引入Flow相关包,由于Flow是基于协程基础开发,引入协程相关包就行:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
这里我们实现一个简单的计时器,数据我们使用ViewModel,创建一个简单的数据流。
class MainViewModel : ViewModel() {
val timeFlow = flow {
var time = 0
while (true) {
emit(time)
delay(1000)
time++
}
}
}
上面简单定义一个冷流Flow,每隔一秒钟time加一,冷流是什么呢,就是需要收集才会发射数据流,后面会介绍热流。布局方面,我们使用Jetpack Compose实现:
@Preview(showBackground = true)
@Composable
fun Content() {
val viewModel: MainViewModel = viewModel()
var times by remember { mutableStateOf(0) }
// 获取LifecycleOwner
val lifecycleOwner = LocalLifecycleOwner.current
Column(
Modifier
.fillMaxSize()
.wrapContentSize(Alignment.Center)
) {
Text(
textAlign = TextAlign.Center,
modifier = Modifier.width(200.dp),
text = "$times",
color = Color.Blue,
fontSize = 26.sp
)
Button(
onClick = {
lifecycleOwner.lifecycleScope.launch {
viewModel.timeFlow.collect { time ->
times = time
}
}
},
modifier = Modifier.width(200.dp)
) {
Text(
textAlign = TextAlign.Center,
text = "START",
color = Color.White,
fontSize = 20.sp
)
}
}
}
上面代码就是一个垂直布局,Text来接收显示计时器的数值,Button用来启动协程,收集数据流,并改变times的值,times是remember包装的变量,会根据值变化,通知Content函数重组并刷新UI。
实际效果如下:
点击按钮开始时,计时器从0开始,每隔一秒,数字改变一下,相当于一个秒表。
我们改变一下接收数据流的地方:
lifecycleOwner.lifecycleScope.launch {
viewModel.timeFlow.collect { time ->
times = time
delay(3000)
}
}
每次collect后,delay 3秒,看下效果:
我们可以看到隔了3秒,才改变一次数值,跟我们要求的秒表效果不一致,这是收集的流和发射的流速度不一致导致的,接收的值都是旧值。我们收集流方法collect改成collectLatest试下:
我们可以看到,数值变化效果正常了,collectLatest看函数名称就知道,收集最新的数据,上一次数据没有处理完,直接丢弃。
总结
至此,我们从一个简单的例子,了解了Flow基本使用方法,Flow用法远不止于此,下篇我们介绍一下,Flow的常见操作符。
创作不易,喜欢的麻烦点赞、评论,以资鼓励。