使用Kotlin Flow做HTTP轮询(三)
原创
©著作权归作者所有:来自51CTO博客作者WongKyunban的原创作品,请联系作者获取转载授权,否则将追究法律责任
其实做HTTP轮询也相当简单,比如,我们现在在《如何在android开发中使用Kotlin Flow(二)》 基础上改成一个HTTP轮询:
class CommentRepository(private val apiService: GetCommentService) {
var isClosed = false
private val dispatcher = Dispatchers.IO
suspend fun getCommentWithId(id: Int): Flow<CommentModel> {
return channelFlow {
while (!isClosed) {
val data = apiService.getCommentWithId(id)
send(data)
delay(5000)
}
}.flowOn(dispatcher)
// flow {
// val data = apiService.getCommentWithId(id)
// emit(data)
// }.flowOn(Dispatchers.IO)
}
fun close() {
dispatcher.cancel()
}
}
这样就完成了一个5秒请求一次HTTP的功能了。我现在来谈谈这个channelFlow。
public fun <T> channelFlow(@BuilderInference block: suspend ProducerScope<T>.() -> Unit): Flow<T> =
ChannelFlowBuilder(block)
它会创建一个冷流对象ChannelFlowBuilder

它最终也是一个Flow对象。我们传给我们的函数,就是上图中的block,最终它会提供一个ProducerScope:

它会给我们提供SendChannel对象,我们用它在我们的block里发送生产出来的数据。在channelFlow里,我们让运行在不同协程上下文的代码生产数据,或者让它们并发生产数据,不管怎么样,这些产生的数据都可以用SendChannel来发送,如(这两个例子是来自官方的):
fun <T> Flow<T>.merge(other: Flow<T>): Flow<T> = channelFlow {
// collect from one coroutine and send it
launch {
collect { send(it) }
}
// collect and send from this coroutine, too, concurrently
other.collect { send(it) }
}
fun <T> contextualFlow(): Flow<T> = channelFlow {
// send from one coroutine
launch(Dispatchers.IO) {
send(computeIoValue())
}
// send from another coroutine, concurrently
launch(Dispatchers.Default) {
send(computeCpuValue())
}
}
因为channelFlow产生的是一个冷流,所以它的启动,也只有在collect末端操作符作用上来时,才会启动。channelFlow是线程安全的,不用担心它会因并发而产生不好的结果。
我们block里的代码,一执行完,channelFlow产生的Flow对象也就结束了。因为它是冷流的原因,为了让它保持工作,上面我用了while循环让它一直工作。
如果想结束它,可以拿到它的协程上下文进行取消操作,如上面的close方法。
大概就这么多先吧。