Яка різниця між плоскою карткою та схемою перемикання в RxJava?


149

Визначення rxjava doc для переключення карти досить розпливчасте, і воно посилається на ту ж сторінку, що і flatmap. Яка різниця між двома операторами?


1
Про неї посилаються на ту ж сторінку, що і плоска карта . Це дійсно так. Але прокрутіть униз до розділу " Інформація, орієнтована на мову ", і відкрийте цікавий оператор. Я думаю, що це слід робити автоматично з TOC, але ... Також ви можете побачити ту саму картину в javadoc .
Руслан Стельмаченко

Відповіді:


180

Відповідно до документації ( http://reactivex.io/documentation/operators/flatmap.html )

switchMapподібно flatMap, але він буде видавати тільки елементи з нових спостережуваних , поки нове подія не випромінюється з джерела спостережуваного.

Мармурова схема показує це добре. Зауважте різницю діаграм:

У switchMapдругій оригінальній емісії ( зелений мармур ) не випромінюється її друга картографічна емісія ( зелений квадрат ), оскільки третя оригінальна емісія ( блакитний мармур ) почалася і вже випромінювала свою першу картова емісію ( блакитний алмаз ). Іншими словами, відбувається лише перша з двох відображених зелених викидів; жоден зелений квадрат не випромінюється, оскільки синій діамант бив його.

В результаті flatMap, всі відображені результати будуть викинуті, навіть якщо вони "застарілі". Іншими словами, і перша, і друга з відображених зелених викидів трапляються - зелений квадрат був би випущений (якби вони використовували послідовну функцію карти; оскільки вони цього не зробили, ви бачите другий зелений діамант, навіть якщо він видається після перший блакитний діамант)

SwitchMap у SwitchMap, якщо оригінал спостережуваних даних випромінює щось нове, попередні викиди більше не дають відображених відображених даних;  це ефективний спосіб уникнути несвіжих результатів

плоска карта

у SwitchMap, якщо оригінал спостережуваних даних випромінює щось нове, попередні викиди більше не дають відображених відображених даних;  це ефективний спосіб уникнути несвіжих результатів


4
Дякую, діаграма дуже корисна. Чи знаєте ви приклад із реального світу, де би використовувався switchMap?
Джуліан Іди

1
@JulianGo тут є приклад: github.com/samuelgruetter/rx-playground/blob/master/… Він використовує .map(func).switch, але це те саме, що .switchMap(func).
Самуель Грюттер

2
На всякий випадок, коли комусь ще потрібен реальний приклад світу switchMap, він може перейти за цим посиланням на посилання, і він зрозуміє, коли використовувати swicthMap замість flatMap.
германович

2
Для прикладу використання SwitchMap від Ben Lesh за допомогою RxJs5 - див. Хвилин 25-26 тут - youtube.com/watch?v=3LKMwkuK0ZE для мене, вже зрозуміли
плоскі карти

7
Мармурова схема показує це добре? Що? Я думаю, якщо ви вже розумієте схему комутації, можливо.
Гельцгейт

166

Я натрапив на це при впровадженні "миттєвого пошуку" - тобто коли користувач набирає текст у текстовому полі, а результати з’являються майже в реальному часі з кожним натисканням клавіші. Здається, рішення:

  1. Майте тему, наприклад PublishSubject of String
  2. У текстовому полі змінити зворотний виклик, викликати .onNext (текст)
  3. застосувати .debounce фільтр для обмеження кількості запитів на сервер
  4. застосувати .switchMap для виконання запиту на сервері - прийняття пошукового терміна та повернення Observable of SearchResponse
  5. застосувати .subscribe з методом, який споживає SearchResponse та оновлює інтерфейс користувача.

У програмі flatMap результати пошуку можуть бути несвіжими, оскільки відповіді на пошук можуть вийти з ладу. Щоб виправити це, слід використовувати SwitchMap, оскільки він гарантує, що старе спостереження відміняється підписку, коли надається більш нова.

Отже, підсумовуючи, flatMap слід використовувати, коли всі результати мають значення, незалежно від їх часу, а SwitchMap слід використовувати лише тоді, коли є результати останньої спостережуваної речовини.


Ви можете перевірити цей приклад у GitHub
Cabezas

95

Немає flatMap обговорення завершено без порівняння і зіставлення з switchMap, concatMapі concatMapEager.

Усі ці методи використовують a, Func1що перетворюють потік у Observables, які потім випромінюються; Різниця полягає в тому, коли повернені Observables підписані і відписані, і якщо і коли ці викиди цих Observables викидаються відповідним ____Mapоператором.

  • flatMapпідписується на якомога більше емітованих Observables. (Це номер, що залежить від платформи. Наприклад, менший номер на Android) Використовуйте це, коли замовлення НЕ важливо, і ви хочете, щоб викиди були якнайшвидше.
  • concatMapпідписується на перший Observableі підписується на наступний лише Observableтоді, коли попереднє завершено. Використовуйте це, коли замовлення важливе і ви хочете заощадити ресурси. Прекрасним прикладом є відстрочка мережевого дзвінка, попередньо перевіривши кеш. За цим зазвичай може супроводжуватися .first()або .takeFirst()уникати зайвих робіт.

    http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

  • concatMapEagerпрацює майже так само, але підписується на якомога більше (залежно від платформи), але видаватиметься лише після завершення попереднього Observable. Ідеально підходить, коли у вас багато паралельної обробки, яку потрібно виконати, але (на відміну від flatMap) ви хочете підтримувати початковий порядок.

  • switchMapпідписується на останній, з яким Observableвін стикається, і скасовує підписку на всі попередні Observables. Це ідеально підходить для таких випадків, як пошукові пропозиції: після того, як користувач змінив свій пошуковий запит, старий запит вже не представляє інтересу, тому він не підписався, а добре проведена кінцева точка Api скасує мережевий запит.

Якщо ви повертаєте Observables, що не має subscribeOnіншої нитки, всі перераховані вище методи можуть вести себе приблизно однаково. Цікава та корисна поведінка з'являється, коли ви дозволяєте вкладеним Observables діяти на власних потоках. Тоді ви можете отримати отримати багато переваг від паралельної обробки, і розумно відписки або не підписувати від ObservableS , які не цікавлять ваші SubscriberS

  • ambможе також представляти інтерес. Враховуючи будь-яку кількість Observables, він випромінює ті самі елементи, що перший Observableвипускає що-небудь. Це може бути корисно, коли у вас є кілька джерел, які могли б / повинні повернути одне і те ж, і ви хочете виконати. наприклад, сортування, ви ambможете швидко сортувати за допомогою злиття та використовувати те, що було швидше.

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- кожне пояснення, з яким switchMap vs flatMapя стикався раніше, пропускав цей важливий аспект, тепер усе зрозуміліше. Дякую.
Енді Рез

55

Колись switchMap колись називався flatMapLatest в RxJS 4.

Це в основному просто передає події з останньої " Оглядової" та відписується від попередньої.


@EpicPandaForce Хоча це суперечить комбінезонуLatest, який видає останні значення кожного разу, коли джерело, що спостерігається, випромінює (не видає один раз).
Майкл Фрай

2
Частково причина, що називається switchMap, полягає в тому, що ви можете самостійно реалізувати цього оператора, використовуючи o.map (...). Switch (). Хоча тоді я б міг уявити, що це MapSwitch, який, схоже, не так легко скочується з язика.
Niall Connaughton,

7

Map, FlatMap, ConcatMap і SwitchMap застосовує функцію або змінює дані, випромінювані спостережуваним.

  • Карта змінює кожен елемент, що випромінюється джерелом, що спостерігається, та видаляє модифікований елемент.

  • FlatMap, SwitchMap та ConcatMap також застосовує функцію до кожного випущеного елемента, але замість повернення модифікованого елемента він повертає Observable, який може випромінювати дані знову.

  • Робота FlatMap та ConcatMap майже однакова. Вони об'єднують елементи, випромінювані кількома спостережуваними, і повертають один спостерігається.

  • Різниця між FlatMap та ConcatMap - це порядок, в якому елементи випромінюються.
  • FlatMap може переплутати елементи, одночасно випромінюючи, тобто порядок випромінюваних елементів не підтримується.
  • ConcatMap зберігає порядок позицій. Але головним недоліком ConcatMap є те, що він повинен чекати, коли кожен спостерігаючий завершить свою роботу, таким чином, асинхронність не підтримується.
  • SwitchMap трохи відрізняється від FlatMap та ConcatMap . SwitchMap скасовує підписки з попереднього джерела. Помітно, коли новий елемент починає випромінювати, таким чином, завжди випромінюючи елементи з поточного спостерігається.

1

Якщо ви шукаєте приклад коду

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

Більше прикладів ви можете подивитися тут https://github.com/politrons/reactive


4
Але ви пропускаєте ключову особливість switchMap, яка відрізняє його від flatMap - лише найсвіжіші спостережувані питання, відміняючи підписку на попередні.
Артем Новіков

3
У цьому прикладі при заміні switchMapна flatMapнього буде працювати точно так само.
Пьотр Віттхен

1

Ось ще один приклад - 101 рядок . Це пояснює для мене річ.

Як було сказано: вона отримує останню спостережувану (найповільнішу, якщо ви хочете) і ігнорує решту.

Як результат:

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

Ви бачите, що A проігнорували.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.