在 Kotlin Coroutines 生产者内部处理取消
Handle cancelation inside Kotlin Coroutines producer
是否可以在生产者构建器内部处理生产者取消?取消订阅回调可能很有用:
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)
}
}
或者可能存在另一种方法来实现这种情况?
首先,你不应该使用 produce
构建器以这种方式适应 API 与监听器,因为在 produce
构建器主体存在时通道会立即关闭并将停止发挥其作用。相反,您应该只创建一个 Channel()
并创建相应的连接。
遗憾的是,频道目前不提供安装取消侦听器的开箱即用方式(请参阅 issue #341)。在通道关闭时立即得到通知的唯一方法是扩展相应的通道 class,这将导致以下代码:
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)
}
}
即将推出的 kotlinx.coroutines 库版本 should expose a Channel.invokeOnClose { ... }
method 可以满足此类用例。
但是,同时有解决此问题的方法。
一种解决方案是
另一种解决方案是使用以下方式生成:
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)
}
}
是否可以在生产者构建器内部处理生产者取消?取消订阅回调可能很有用:
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)
}
}
或者可能存在另一种方法来实现这种情况?
首先,你不应该使用 produce
构建器以这种方式适应 API 与监听器,因为在 produce
构建器主体存在时通道会立即关闭并将停止发挥其作用。相反,您应该只创建一个 Channel()
并创建相应的连接。
遗憾的是,频道目前不提供安装取消侦听器的开箱即用方式(请参阅 issue #341)。在通道关闭时立即得到通知的唯一方法是扩展相应的通道 class,这将导致以下代码:
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)
}
}
即将推出的 kotlinx.coroutines 库版本 should expose a Channel.invokeOnClose { ... }
method 可以满足此类用例。
但是,同时有解决此问题的方法。
一种解决方案是
另一种解决方案是使用以下方式生成:
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)
}
}