Kotlin Flow简单使用

作者: 奔跑吧李博 | 来源:发表于2023-01-09 12:36 被阅读0次
什么是流?

从流的方向来观察,我们称原始数据为上流,对数据进行一系列处理后,最终的数据为下流。
从流的属性来观察,我们认为生产者在上流生产数据,消费者在下流消费数据。

为什么引进Flow?

Flow 是 Kotlin 官方基于协程构建的用于响应式编程的API。响应式编程简单来说就是使用异步数据流进行编程 。协程中,使用挂起函数仅可以异步返回单个值,而 Flow 则可以异步返回多个值,并补全kotlin语言中响应式编程的空白。

Flow常见的操作
  • 生产者消费者例子
    suspend fun collect() {
        flow {
            //发射数据
            emit(5)
        }.collect {
            //消费者
            Log.i("minfo", "value=$it")
        }
    }

通过flow函数构造一个flow对象,然后通过调用flow.collect收集数据。
flow函数的闭包为生产者的生产逻辑,collect函数的闭包为消费者的消费逻辑。

流的三要素:原始数据、对数据的操作、最终数据,对应到Flow上也是一样的。
flow的闭包里我们看做是原始数据,而filter、map、catch等看做是对数据的操作,collect闭包里看做是最终的数据。

  • 寻找1~1000内大于500,并且是7的倍数的数
    suspend fun findNum() {
        var flow = flow {
            for (i in 1..1000) {
                emit(i)
            }
        }.filter {
            it > 500 && it % 7 == 0
        }

        flow.collect {
            Log.i("minfo", "num=$it")
        }
    }
  • 实现一个计时器的效果,每秒钟更新一次时间
    简单布局:
<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">

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="90dp"
        android:text="0"
        android:textSize="18sp"/>

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start"
        app:layout_constraintTop_toBottomOf="@id/tv_time"
        app:layout_constraintStart_toStartOf="@id/tv_time"
        app:layout_constraintEnd_toEndOf="@id/tv_time"
        android:layout_marginTop="20dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

点击事件触发:

class MainActivity : AppCompatActivity() {
    private lateinit var tvTime: TextView
    private lateinit var btnStart: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        tvTime = findViewById(R.id.tv_time)
        btnStart = findViewById(R.id.btn_start)
        btnStart.setOnClickListener {
             timeFlow()
        }
    }

    suspend fun timeFlow() {
    fun timeFlow() {
        var timeFlow = flow {
            var time = 0
            while (true) {
                emit(time)
                kotlinx.coroutines.delay(1000)  //使用挂起函数delay
                time++
            }
        }
    }
}

现在的代码下,点击start,会不会就开始发送数据了,在这种场景下不会。因为使用flow构建函数构建出的Flow是属于Cold Flow,也叫做冷流。所谓冷流就是在没有任何接受端的情况下,Flow是不会工作的。只有在有接受端的情况下,Flow闭包中的代码就会自动开始执行。

修改代码让例子生效:

class MainActivity : AppCompatActivity() {
    private lateinit var tvTime: TextView
    private lateinit var btnStart: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        tvTime = findViewById(R.id.tv_time)
        btnStart = findViewById(R.id.btn_start)
        btnStart.setOnClickListener {
            GlobalScope.launch(Dispatchers.Main) {
                timeFlow()
            }
        }
    }

    private suspend fun timeFlow() {
        flow {
            var time = 0
            while (true) {
                emit(time)
                kotlinx.coroutines.delay(1000)  //使用挂起函数delay
                time++
            }
        }.collect {
            tvTime.text = "$it"
        }
    }
}

使用collect函数进行数据接收,由于Flow的collect函数是一个挂起函数,因此必须在协程作用域或其他挂起函数中才能调用。

冷流和热流的区别:

冷流 🥶 热流 🥵
不消费,不生产,多次消费,多次生产,只有1个观察者 f有没有消费者都会生产数据

相关文章

网友评论

    本文标题:Kotlin Flow简单使用

    本文链接:https://www.haomeiwen.com/subject/npwycdtx.html