簡體   English   中英

處理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()並創建相應的連接。

不幸的是,頻道目前不提供安裝取消偵聽器的開箱即用方式(參見問題#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)
    }
}

即將推出的kotlinx.coroutines庫版本應公開 Channel.invokeOnClose Channel.invokeOnClose { ... }方法以滿足此類用例。

但是,有解決方案同時具有此行為。 正如Roman Elizarov建議的那樣,一種解決方案是將您正在尋找的頻道子類化。

另一種解決方案是使用以下方式生產:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM