Операторы лежат в основе Kotlin Flow, как и любого реактивного фреймворка. Это позволяет манипулировать элементами по мере их перехода от наблюдаемого к наблюдателю.

Вот 9 очень важных, но менее известных операторов Kotlin Flow с графикой и примерами.

Давайте начнем!

1. Уменьшить

Оператор сокращения позволяет выполнить операцию над всеми элементами потока, чтобы свести их в один элемент.

Например, приведенная ниже функция сокращения выполняет суммирование всех элементов, и поэтому мы получаем результат 6.

flowOf(1, 2, 3)
    .reduce { acc, value -> acc + value }
Output:
6

Здесь результат должен быть того же типа, что и элементы, т. е. если у вас поток Integer, вы не можете получить в результате String.

2. Сложите

Аналогичен reduce, но допускает результат любого типа.

Например, здесь мы начинаем со строки и выполняем конкатенацию строк всех элементов.

flowOf(1, 2, 3)
    .fold("hello", { acc, value -> acc + value })
Output:
hello123

3. Отказаться

Оператор Debounce выдает элемент из потока только в том случае, если в течение определенного промежутка времени он не излучал другой элемент.

Например, предположим, что вы разрабатываете окно поиска, и у вас есть поток пользовательского ввода.

В этом случае вы захотите, чтобы поисковый запрос запускался только тогда, когда пользователь не печатает в течение 500 мс, иначе вы в конечном итоге будете запрашивать столько раз. Таким образом, пока пользователь вводит другой символ до истечения 500 мс, debounce не отправит этот элемент. Однако последний элемент всегда будет отправлен, если пользователь ничего не вводит в течение 500 мс.

flow {
    emit(1)
    delay(90)
    emit(2)
    delay(90)
    emit(3)
    delay(1010)
    emit(4)
    delay(1010)
    emit(5)
}.debounce(1000)
Output:
3, 4, 5

4. Образец

Подобно debounce, он также используется для фильтрации элементов из Flow, но имеет одно важное отличие — вместо проверки интервала от последнего элемента оператор sample будет запускаться периодически и отправлять 1 последний элемент за интервал.

Например, здесь у нас есть поток, который продолжает выдавать элемент каждые 50 мс, и если мы применим sample из 100 мс, мы получим каждый второй элемент.

flow {
    repeat(10) {
        emit(it)
        delay(50)
    }
}.sample(100)
Output:
1,3,5,7,9

Помните, если бы мы использовали здесь debounce, мы получили бы только элемент 9 .

5. плоская картаОбъединение

Оператор flatmapMerge сопоставляет каждый элемент потока с новым потоком, предоставленным операцией преобразования, а затем объединяет элементы этих потоков и сглаживает их.

Рассмотрим следующий пример

flowOf(1, 2, 3)
    .flatMapMerge { flowOf("$it a", "$it b") }
Output:
2a, 2b, 1a, 1b, 3a, 3b

Здесь Flow элементов 1, 2 и 3 сопоставляется с новым Flow, который испускает 2 элемента на 1 элемент предыдущего Flow.
Затем эти потоки объединяются и выравниваются, поэтому при сборе в конце вы получите плоские элементы из всех потоков.

6. плоская картаConcat

Аналогично flatmapMerge, но здесь потоки объединяются, а не объединяются.

Помните, что flatmapMerge имеет лучшую производительность, так как может обрабатывать потоки параллельно.

Пример выше говорит сам за себя.

7. Буфер

Это немного сложно понять, так как это на самом деле не меняет поток элементов, а скорее помогает с производительностью.

Рассмотрим этот пример

flowOf("A", "B", "C")
    .onEach  { delay(300) }
    .collect { println("$it") }
// Output takes 900ms as all items are processed sequentially

Здесь у нас есть поток из 3 элементов, и они выпускаются сразу.

Однако, поскольку у нас есть оператор onEach с задержкой 300 мс, сбор будет обрабатывать все элементы последовательно, а это означает, что для сбора потребуется всего 900 мс.

Если мы добавим буфер между оператором onEach и collect, он создаст отдельную сопрограмму для параллельного сбора элементов от оператора onEach в соответствии с предоставленной емкостью buffer. Это позволит нам собрать все элементы за 300 мс, так как все операторские операции не должны выполняться последовательно.

flowOf("A", "B", "C")
    .onEach  { delay(300) }
    .buffer(3)
    .collect { println("$it") }
// Output takes 300ms as all items are processed in parallel at buffer operator and delivered to collect immediately.

8. Комбинируйте

Этот оператор объединяет два потока с предоставленной функцией operation.

Здесь — Последние элементы Потоков всегда объединяются.

Как показано во фрагменте ниже, первый поток создает элементы 1 и 2. Таким образом, только последний элемент 2 объединяется с каждым элементом второго потока.

flowOf("1", "2")
    .combine(flowOf("a", "b", "c"), {a, b -> a + b })
Output:
2a, 2b, 2c

9. молния

Подобно combine , это также объединяет два потока, но будет транслировать один элемент, когда оба потока испускают по 1 элементу каждый.

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

flowOf("1", "2")
    .zip(flowOf("a", "b", "c"), {a, b -> a + b })
Output:
1a, 2b

Как показано здесь, из результирующего потока выдаются только два элемента zipped, так как первый Flow содержит только два элемента.

Вот и все на сегодня, надеюсь, вы узнали что-то новое!

Спасибо за вашу поддержку!

Если вам нравится то, что вы читаете, обязательно 👏 👏👏 это ниже — как писатель это означает мир!

Подпишитесь на Canopasилисвяжитесь с нами в Twitter, чтобы получать новости об интересных статьях!