萌萌の初音
萌萌の初音
发布于 2022-07-05 / 952 阅读
0

Kotlin Flow的简单使用(含StateFlow)

kotlin flow介绍

  1. flow基于kotlin携程;
  2. 使用方式类似于RxJava但更简单;
  3. flow可以转换成LiveData;
  4. 结合协程的作用域,避免内存泄漏;

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()
        
    }
}