kotlin flow介绍
- flow基于kotlin携程;
- 使用方式类似于RxJava但更简单;
- flow可以转换成LiveData;
- 结合协程的作用域,避免内存泄漏;
flow的使用
1. 简单使用
var test1 = flow<Int> { emit(getInt()) }
private suspend fun getInt(): Int = withContext(Dispatchers.IO) {
delay(1000)
1
}
fun showInt() {
viewModelScope.launch {
test1.collect {
println(it)
}
}
}
在该示例中getInt()相当于我们的网络请求等耗时操作,通过emit发送结果,collect进行数据消费,collect是挂起函数,需要在CoroutineScope执行。以上就是flow最简单的实现。
2. flowOn
flowOn决定上游线程执行类型,类似于RxJava的subscribeOn。
flow<Int> {
emit(getInt())
}.flowOn(Dispatchers.IO)
在该示例中flowOn(Dispatchers.IO)代表在IO中执行。
3. map操作符
可以对流进行操作,如转换数据等操作,然后再传入collect。
flow<Int> {
emit(getInt())
}.map {
it -> "$it"
}.flowOn(Dispatchers.IO).collect {
println(it)
}
在该示例中println(it)的it已经是String类型。
4. transform操作符
用于类型转换,在泛型配置中限定转换类型。
flow {
emit(getInt())
}.transform<Int, String> {
emit("$it")
}.flowOn(Dispatchers.IO).collect {
println(it)
}
在该示例中规定消费类型从Int转换为String。
5. buffer操作符
用于并发数据。
flow {
(1..3).forEach { _ ->
emit(getInt())
}
}.buffer(5).flowOn(Dispatchers.IO).collect {
println(it)
}
在该示例中,(1…3).forEach的3组会直接完成循环传递数据,不用等待消费完再执行。
6. zip与combine操作符
用于两个流合并为一个流,两个操作符区别为:zip两个流长度按短的流处理,短的流处理完毕后就不再处理,combine会把两个流全部处理完,如果两个流长度不一致,就会返回短的流最后的数据。
suspend fun test() {
val flow1 = (1..3).asFlow();
val flow2 = arrayListOf<String>("1", "2", "3", "4", "5").asFlow()
flow1.zip(flow2) {
value1, value2 -> "$value1: $value2"
}.collect {
println(it)
}
}
该示例中zip替换为combine即可。
7. flowOf
在执行流前flowOf内的方法会最先运行,不受flowOn影响。
flowOf {
yourFun() //这个方法不受Dispatchers.IO影响
}.flowOn(Dispatchers.IO).collect {
}
8. launchIn
使用在没有suspend修饰符的方法中不用外套一层launch{}。
lifecycleScope.launchWhenCreated {
flow{
yourFun()
}.collect {
...
}
}
flow{
yourFun()
}.onEach {
...
}.launchIn(this.lifecycleScope)
使用lunchIn可以简化代码。
StateFlow
StateFlow是与LiveData相近的流形式,可代替LiveData。StateFlow必须要默认值。
简单使用
class DemoViewModel : ViewModel {
private val _demoFlow = MutableStateFlow<MutableList<String>>(arrayListOf())
val demoFlow: StateFlow<MutableList<String>> = _demoFlow
fun initData() {
_demoFlow.value = arrayListOf("1", "2", "3")
}
}
class DemoActivity : AppCompatActivity {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
demoViewModel.demoFlow.onEach {
yourFun()
}.launchIn(this.lifecycleScope)
demoViewModel.initData()
}
}