是否可以在生产者构建者内部处理生产者取消?退订回调可能很有用:
private fun changes(key: String) = produce<Unit>(UI, CONFLATED) {
val listener = OnSharedPreferenceChangeListener { _, changedKey ->
if (key == changedKey) offer(Unit)
}
prefs.registerOnSharedPreferenceChangeListener(listener)
???.onCancel {
prefs.unregisterOnSharedPreferenceChangeListener(listener)
}
}
或者可能存在实现这种情况的另一种方法?
答案 0 :(得分:4)
首先,您不应该使用produce
构建器来通过监听器调整API,因为在produce
构建器主体中,通道会立即关闭并且将停止为其提供服务功能。相反,您应该只创建一个Channel()
并创建相应的连接。
不幸的是,通道当前不提供开箱即用的方式来安装取消监听器(请参阅issue #341)。在通道关闭时立即获得通知的唯一方法是扩展相应的通道类,这将导致以下代码:
private fun changes(key: String): ReceiveChannel<Unit> = object : ConflatedChannel<Unit>() {
val listener = OnSharedPreferenceChangeListener { _, changedKey ->
if (key == changedKey) offer(Unit)
}
init {
prefs.registerOnSharedPreferenceChangeListener(listener)
}
override fun afterClose(cause: Throwable?) {
prefs.unregisterOnSharedPreferenceChangeListener(listener)
}
}
答案 1 :(得分:1)
kotlinx.coroutines库should expose a Channel.invokeOnClose { ... }
method的即将发布版本可以满足此类用例。
但是,在此期间,有解决方案可以解决此问题。 一种解决方案是subclass the channel you're looking for, as Roman Elizarov suggested.
另一种解决方案是使用产生方式如下:
fun SharedPreferences.changes(key: String) = produce {
val changesChannel = ConflatedChannel<Unit>()
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, changedKey ->
if (key == changedKey) changesChannel.offer(Unit)
}
registerOnSharedPreferenceChangeListener(listener)
try {
for (change in changesChannel) {
send(change)
}
} finally {
unregisterOnSharedPreferenceChangeListener(listener)
}
}