这些flow常见API的使用,你一定需要掌握!(四)

1,208 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情

本篇文章将是介绍flow一些常见API系列的第四篇文章,希望能够帮助大家更好的掌握flow使用,熟练的应用于各种场景。

历史文章

这些flow常见API的使用,你一定需要掌握!(一)
这些flow常见API的使用,你一定需要掌握!(二)
这些flow常见API的使用,你一定需要掌握!(三)

combine()传递两个流合并后的结果

public fun <T1, T2, R> Flow<T1>.combine(flow: Flow<T2>, transform: suspend (a: T1, b: T2) -> R): Flow<R> = flow {
    combineInternal(arrayOf(this@combine, flow), nullArrayFactory(), { emit(transform(it[0] as T1, it[1] as T2)) })
}

这个方法有些类似于rxjava中的zip()方法,将两个流的结果通过某种方式合并并发送给下游流,看下使用:

fun flat() {
    GlobalScope.launch {
        flow {
            emit(10)
        }.combine(flow {
            emit(20)

        }) { i, j ->
            "$i-$j"
        }.collect {
            println("flat collect: $it")
        }
    }
}

执行结果:

image.png

debounce()限流

public fun <T> Flow<T>.debounce(timeoutMillis: Long): Flow<T> {
    require(timeoutMillis >= 0L) { "Debounce timeout should not be negative" }
    if (timeoutMillis == 0L) return this
    return debounceInternal { timeoutMillis }
}

这个方法可是十分的有用,就是用来限流的,这里举个例子阐述:

调用debounce(200)后,当上游发送一次数据后,只有在200ms之内不再发生上游流到下游流的数据传递,之前发送的数据才能传递到下游流进行消费,否则之前发送的数据都会丢弃并重新开始即使200内是否发送数据传递,直到没发生后下游流才能收到消费。

fun flat() {
    GlobalScope.launch {
        flow {
            for (i in 0..7) {
                emit(i)
            }
        }.debounce(200)
            .collect {
            println("flat collect: $it")
        }
    }
}

如上,在for循环中循环发送数据,数据发送的间隔肯定每次都是小于200ms的,所以最终只有发送最后一条数据7才能最终能达到下游流进行消费。输出结果也是如此:

image.png

下面我们改造下上面的代码,每次发送数据后增加个休眠210ms的操作,关键代码:

flow {
    for (i in 0..7) {
        emit(i)
        delay(210)
    }
}

输出:

image.png

可以看到,从0到7数据都能顺利被下游流接受,就是因为每次休眠210ms是大于ddebounce(200)方法指定的200ms。

sample()按时间间隔采样

image.png

这个方法和上面的debounce()方法的区别是:比如sample(200)是每隔200ms取最后一次上游流发送的数据,举个例子:

做一个最近聊天消息列表,每个消息item会展示最后的一条聊天消息摘要,聊天大群中聊天消息频繁发送接受就会触发频繁的聊天消息摘要的刷新,这个时候就非常适合sample()发挥,比如每隔200ms取该聊天大群的最后一条聊天消息作为摘要,这样就降低了列表的刷新频率,又能及时显示最新的聊天消息摘要,所谓一举两得。

举个例子:

fun flat() {
    GlobalScope.launch {
        flow {
            for (i in 0..7) {
                emit(i)
                delay(110)
            }
        }.sample(200)
            .collect {
            println("flat collect: $it")
        }
    }
}

执行结果如下:

image.png

每隔200ms取一次上游流数据,第一次上游发送0休眠110ms没到200ms,那就发送1再休眠你110ms,此时肯定超过了200ms,所以取最后的发送数据1发送给下游流消费,之后的依次如此。