Android技术知识Android开发经验谈Android开发

Kotlin Flow简单使用

2023-01-09  本文已影响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闭包里看做是最终的数据。

    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有没有消费者都会生产数据
上一篇 下一篇

猜你喜欢

热点阅读