Ручка отмены внутри производителя Kotlin Coroutines - PullRequest
0 голосов
/ 25 июня 2018

Возможно ли обработать отмену производителя внутри самого производителя?Может быть полезно отписаться от обратного вызова:

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)
        }
}

Или, может быть, существует другой способ реализовать этот случай?

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

Предстоящая версия библиотеки kotlinx.coroutines должна предоставлять метод Channel.invokeOnClose { ... } для удовлетворения таких случаев использования.

Однако, есть решения для такого поведения в настоящее время.Одним из решений является создание подкласса канала, который вы ищете, как предложил Роман Елизаров.

Другое решение заключается в использовании производства следующим образом:

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)
    }
}
0 голосов
/ 26 июня 2018

Прежде всего, вам не следует использовать компоновщик produce для такой адаптации API со слушателями, поскольку при существовании из тела компоновщика produce канал немедленно закрывается и перестает выполнять свою функцию.Вместо этого вы должны просто создать Channel() и создать соответствующие соединения.

К сожалению, в настоящее время каналы не предоставляют готового способа установки прослушивателей отмены (см. выпуск # 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)
    }
}
...