将听众变成 kotlin 协程通道
Turning listeners into kotlin coroutine channels
我想使用几个函数来处理 Channel
的管道。主要的是 globalLayouts
,我从框架侦听器创建了一个 Channel
:
fun View.globalLayouts(): ReceiveChannel<View> =
Channel<View>().apply {
val view = this@globalLayouts
val listener = ViewTreeObserver.OnGlobalLayoutListener {
offer(view)
}
invokeOnClose {
viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
viewTreeObserver.addOnGlobalLayoutListener(listener)
}
@UseExperimental(InternalCoroutinesApi::class)
fun <E> ReceiveChannel<E>.distinctUntilChanged(context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel<E> =
GlobalScope.produce(context, onCompletion = consumes()) {
var last: Any? = Any()
consumeEach {
if (it != last) {
send(it)
last = it
}
}
}
fun View.keyboardVisibility(): ReceiveChannel<KeyboardVisibility> {
val rect = Rect()
return globalLayouts()
.map {
getWindowVisibleDisplayFrame(rect)
when (rect.height()) {
height -> KeyboardVisibility.HIDDEN
else -> KeyboardVisibility.SHOWN
}
}
.distinctUntilChanged()
}
我有一个 CoroutineScope
叫 alive
:
val ControllerLifecycle.alive: CoroutineScope
get() {
val scope = MainScope()
addLifecycleListener(object : Controller.LifecycleListener() {
override fun preDestroyView(controller: Controller, view: View) {
removeLifecycleListener(this)
scope.cancel()
}
})
return scope
}
然后我做:
alive.launch {
root.keyboardVisibility().consumeEach {
appbar.setExpanded(it == KeyboardVisibility.HIDDEN)
}
}
此代码开始工作正常,但我得到
kotlinx.coroutines.JobCancellationException: Job was cancelled; job=JobImpl{Cancelled}@811031f
一旦我的 alive
范围被销毁。在 globalLayouts
中调用 invokeOnClose
之后。我做错了什么以及如何调试它?
明白了 - 代码工作正常,但是
viewTreeObserver.removeOnGlobalLayoutListener(listener)
被窃听 CoordinatorLayout
。
我想使用几个函数来处理 Channel
的管道。主要的是 globalLayouts
,我从框架侦听器创建了一个 Channel
:
fun View.globalLayouts(): ReceiveChannel<View> =
Channel<View>().apply {
val view = this@globalLayouts
val listener = ViewTreeObserver.OnGlobalLayoutListener {
offer(view)
}
invokeOnClose {
viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
viewTreeObserver.addOnGlobalLayoutListener(listener)
}
@UseExperimental(InternalCoroutinesApi::class)
fun <E> ReceiveChannel<E>.distinctUntilChanged(context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel<E> =
GlobalScope.produce(context, onCompletion = consumes()) {
var last: Any? = Any()
consumeEach {
if (it != last) {
send(it)
last = it
}
}
}
fun View.keyboardVisibility(): ReceiveChannel<KeyboardVisibility> {
val rect = Rect()
return globalLayouts()
.map {
getWindowVisibleDisplayFrame(rect)
when (rect.height()) {
height -> KeyboardVisibility.HIDDEN
else -> KeyboardVisibility.SHOWN
}
}
.distinctUntilChanged()
}
我有一个 CoroutineScope
叫 alive
:
val ControllerLifecycle.alive: CoroutineScope
get() {
val scope = MainScope()
addLifecycleListener(object : Controller.LifecycleListener() {
override fun preDestroyView(controller: Controller, view: View) {
removeLifecycleListener(this)
scope.cancel()
}
})
return scope
}
然后我做:
alive.launch {
root.keyboardVisibility().consumeEach {
appbar.setExpanded(it == KeyboardVisibility.HIDDEN)
}
}
此代码开始工作正常,但我得到
kotlinx.coroutines.JobCancellationException: Job was cancelled; job=JobImpl{Cancelled}@811031f
一旦我的 alive
范围被销毁。在 globalLayouts
中调用 invokeOnClose
之后。我做错了什么以及如何调试它?
明白了 - 代码工作正常,但是
viewTreeObserver.removeOnGlobalLayoutListener(listener)
被窃听 CoordinatorLayout
。