Reputation: 103
Is it possible to handle producer cancelation inside producer builder itself? It could be useful to unsubscribe from callback:
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)
}
}
Or may be exists another way to implement this case?
Upvotes: 4
Views: 1309
Reputation: 11529
An upcoming version of the kotlinx.coroutines library should expose a Channel.invokeOnClose { ... }
method to satisfy such use cases.
However, there are solutions to have this behavior in the meantime. One solution is to subclass the channel you're looking for, as Roman Elizarov suggested.
Another solution is to use produce the following way:
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)
}
}
Upvotes: 2
Reputation: 28648
First of all, you should not use produce
builder to adapt API with listeners in this way, because on the exist from the produce
builder body the channel is immediately closed and would cease to serve its function. Instead, you should just create a Channel()
and create the corresponding connections.
Unfortunately, channels do not currently provide an out-of-the-box way to install cancellation listeners (see issue #341). The only way to get immediately notified on the channel close is to extend the corresponding channel class, which leads to the following code:
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)
}
}
Upvotes: 3