Android 如何从Kotlin协程流中的两次发射中仅发射一个结果?

Android 如何从Kotlin协程流中的两次发射中仅发射一个结果?,android,kotlin-coroutines,kotlin-coroutines-flow,Android,Kotlin Coroutines,Kotlin Coroutines Flow,我有这样一个流程: fun createRawDataFlow() = callbackFlow<String> { SensorProProvider.getInstance(this@MainActivity).registerDataCallback { sensorProDeviceInfo, bytes -> val dataString = bytes.map { it.toString() }.reduce { acc, s -> &

我有这样一个流程:

fun createRawDataFlow() = callbackFlow<String> {
    SensorProProvider.getInstance(this@MainActivity).registerDataCallback { sensorProDeviceInfo, bytes ->
        val dataString = bytes.map { it.toString() }.reduce { acc, s -> "$acc, $s" }
        val hexString = HEXUtils.byteToHex(bytes)
        Log.e("onDataReceived", "deviceInfo: ${sensorProDeviceInfo.deviceIdentify}, dataSize:${bytes.size}, data:$dataString")
        offer(hexString)
    }
    awaitClose {  }
}


GlobalScope.launch(Dispatchers.IO) {
    createRawDataFlow()
        .map {
            Log.e("onDataReceived", "map2: ${Thread.currentThread().name}")
            // what I want is collecting 10 emits of sensor's data, and return a list of them
            // arraylistOf<String>(/* 10 hexStrings here*/)
        }
        .flowOn(Dispatchers.IO)
        .collect {
            Log.e("onDataReceived", "thread: ${Thread.currentThread().name}, hexData:$it")
        }
}
fun createRawDataFlow()=callbackFlow{
SensorProProvider.getInstance(this@MainActivity).registerDataCallback{sensorProdDeviceInfo,字节->
val dataString=bytes.map{it.toString()}.reduce{acc,s->“$acc,$s”}
val hexString=HEXUtils.byteToHex(字节)
Log.e(“onDataReceived”,“deviceInfo:${SensorProdDeviceInfo.DeviceIdentity},dataSize:${bytes.size},data:$dataString”)
报价(十六进制字符串)
}
等待关闭{}
}
GlobalScope.launch(Dispatchers.IO){
createRawDataFlow()
.地图{
Log.e(“onDataReceived”,“map2:${Thread.currentThread().name}”)
//我想要的是收集10个传感器的数据发射,并返回它们的列表
//arraylistOf(/*10个十六进制字符串)
}
.flowOn(Dispatchers.IO)
.收集{
Log.e(“onDataReceived”,“thread:${thread.currentThread().name},hexData:$it”)
}
}
就像代码中的注释一样。我想从流中收集10个十六进制字符串,因为这些字符串来自同一时间段,然后将它们打包到数组列表中以返回。我怎样才能做到这一点?是否有类似于map的操作员执行此操作?顺便说一句,请原谅我的英语不好。

首先你要申请

fun Flow.take(计数:Int):Flow
返回包含第一个计数元素的流。当使用计数元素时,原始流将被取消。如果计数不是正数,则引发IllegalArgumentException

然后你申请

suspend fun Flow.toCollection(目的地:C):C
将给定的流收集到目标

take
toCollection
之间,如果需要,可以进行其他操作。这就是它的整体外观:

val hexList:List=createRawDataFlow().take(10)//获取前10项
.map{…}//执行一些(可选)映射
.toCollection(mutableListOf())
//流程取消(所有项目都已消耗)后,元素将显示在hexList中
文档


如果您需要批量收集,并且不想取消原始流,则可以调整发射流函数,使其保留值缓存

/*
*返回至少包含[batchSize]个整数的列表。
*/
流的乐趣(cacheSize:Int=10):流{
变量计数器:Int=0
val缓存:MutableList=mutableListOf()
回流{
while(currentCoroutineContext().isActive){
cache.add(计数器++)
如果(cache.size>=cacheSize){
发射(缓存)
cache.clear()
}
延迟(500L)//延迟仅用于模拟传入的传感器数据
}
}
}
通用解决方案

为了使它更通用一点,我在流上创建了一个通用扩展函数,您可以将它应用于任何您想要返回批处理列表的流

假设我们有一个
无穷大的整数流

fun infiniteFlow():流{
变量计数器:Int=0
回流{
while(currentCoroutineContext().isActive){
发射(计数器++)
延迟(250L)//延迟仅用于模拟传入的传感器数据
}
}
}
批处理
扩展功能:

/**
*将流映射到流。列表大小至少为[batchSize]
*/
乐趣流。批处理(batchSize:Int=10):流{
val缓存:MutableList=mutableListOf()
返回图{
cache.apply{add(it)}
}.filter{it.size>=batchSize}
.地图{
mutableListOf().apply{//复制列表并清除缓存
addAll(缓存)
cache.clear()
}
}
}
注意:这只是一个例子。它没有针对边缘情况进行优化或测试

然后,您可以使用以下功能:

infiniteFlow().batch(batchSize=12).收集{println(it)}

首先,感谢您的回复。我认为我在描述我的问题时做得不好。您的解决方案在前10项中确实运行良好,但情况是传感器不断发送数据,直到我退出应用程序,因此,不应取消原始流,并在某个时间继续处理即将到来的10个字符串包。我刷新了有关缓冲区的文档,但我不确定它是否能起作用,因为我以前从未使用过。没问题。我在这里看到的唯一解决方案是调整发射流并在那里引入缓存。我更新了我的答案,给出了一个例子。非常感谢你的快速回复。我相信这就是我想要的。重要的是,这个解决方案真的帮助我打开心扉。