использование сопрограмм для устранения дребезга

Имея функцию updateData(id:String, data: Any?), которая будет обновлять некоторые данные относительно id. Хотел бы обновить только последние данные, если этот вызов для одного и того же id слишком рано один за другим, предыдущий следует отбросить.

    private var _lastId = ""
    private var _lastCallJob: Job? = null
    private fun debouncingUpdateData(id: String, data: Any?) {

        if (_lastId == id) {
            _lastCallJob?.cancel()
            _lastCallJob = launch {
                delay(20)
                updateData(id, data)
            }
        } else {
            _lastId = id
            _lastCallJob = launch {
                delay(20)
                updateData(id, data)
            }
        }
    }

эта реализация отменит ранее запущенный _lastCallJob (незавершенный, скорее всего, все еще ждет 20 миллисекунд), только если идентификатор тот же.

Но это не работает для случая типа id="1", id="2", id="3"

поэтому при вызове типа:

debouncingUpdateData("1", data)
debouncingUpdateData("2", data)
debouncingUpdateData("1", data)

3-й вызов для id==="1" все еще может выйти (даже если 1-й все еще находится в диапазоне задержки 20 миллисекунд), так как _lastId было изменено на "2".

есть ли лучший способ сделать устранение дребезга с помощью сопрограмм?


person lannyf    schedule 13.05.2020    source источник
comment
Вы рассматривали возможность использования Flow и его встроенного метода debounce? kotlin.github.io/kotlinx. сопрограммы/kotlinx-coroutines-ядро/   -  person fraggjkee    schedule 13.05.2020
comment
@fraggjkee, не думал, просто используйте ту версию kotlin, которую мы используем. спасибо! Признайте, что вы еще не знаете, как использовать Flow, как это поможет для этого нескольких идентификаторов, вызывающих один и тот же функциональный случай?   -  person lannyf    schedule 13.05.2020
comment
в качестве быстрой идеи вы можете создать канал сопрограммы и публиковать в нем обновления идентификатора. Затем вы можете преобразовать этот канал в поток с помощью существующей функции asFlow. Последним шагом будет добавление метода debounce к этому потоку и просто наблюдение за его выбросами и реагирование по мере необходимости (загрузка данных и т. д.). Очень похоже на то, что я сделал бы с Rx — Subject + debounce, но с использованием Coroutines & Flow.   -  person fraggjkee    schedule 13.05.2020
comment
Похоже, будет больше кода (посмотрю), может быть, просто добавят карту (id для работы) с кодом, который у меня есть.   -  person lannyf    schedule 13.05.2020


Ответы (1)


не уверен, есть ли какая-то более простая библиотечная функция, но кажется, что это устраняет дребезг для нескольких случаев id

    private val idToJobMap = HashMap<String, Job>()
    private fun debouncingUpdateData(id: String, data: Any?) {

        idToJobMap[id]?.let { job ->
            job.cancel()
        }
        idToJobMap[id] = launch {
            delay(20)
            idToJobMap.remove(id)
            updateData(data)
        }
    }
person lannyf    schedule 14.05.2020