callbackFlow
将监听外部(其他线程)的不定时回调转为Flow,并在Flow取消时同步取消监听
如下,是一个温度监听类,每隔1秒发送数据
interface TemperatureListener {
fun onTemperatureChanged(value: Double)
}
class TemperatureSensor {
private var listener: TemperatureListener? = null
private var senderJob: Job? = null
fun register(listener: TemperatureListener) {
this.listener = listener
println("传感器:开始监听")
senderJob = CoroutineScope(Dispatchers.Default).launch {
var temperature = 25.0
while (isActive) {
delay(1_000)
listener.onTemperatureChanged(temperature)
temperature += 0.5
}
}
}
fun unregister() {
senderJob?.cancel()
senderJob = null
listener = null
println("传感器:停止监听")
}
}
若普通调用,需要自行注册和取消注册
@Test
fun runCallbackExample() = runBlocking {
println("------------------------------------------------------------------------------------------------------------------------------------------------------")
val sensor = TemperatureSensor()
val listener = object : TemperatureListener {
override fun onTemperatureChanged(value: Double) {
println("普通回调收到温度:$value")
}
}
sensor.register(listener)
delay(2_100)
sensor.unregister()
println("------------------------------------------------------------------------------------------------------------------------------------------------------")
}
传感器:开始监听
普通回调收到温度:25.0
普通回调收到温度:25.5
传感器:停止监听
如下新增扩展函数,将监听过程转为Flow,可以流式处理,并绑定相关生命周期
fun TemperatureSensor.temperatureFlow(): Flow<Double> = callbackFlow {
val listener = object : TemperatureListener {
override fun onTemperatureChanged(value: Double) {
trySend(value)
}
}
register(listener)
// collect 被取消时,注销传感器监听
awaitClose {
unregister()
}
}
@Test
fun runCallbackFlowExample() = runBlocking {
println("------------------------------------------------------------------------------------------------------------------------------------------------------")
val sensor = TemperatureSensor()
val collectJob = launch {
sensor.temperatureFlow().collect { temperature ->
println("收到温度:$temperature")
}
}
// 收集两次每隔 1 秒发送的温度
delay(2_100)
collectJob.cancelAndJoin()
// 取消 collect 后,awaitClose 会调用 sensor.unregister()
println("------------------------------------------------------------------------------------------------------------------------------------------------------")
}
传感器:开始监听
收到温度:25.0
收到温度:25.5
传感器:停止监听