Когда вы используете map
против flatMap
в RxJava ?
Скажем, например, мы хотим отобразить файлы, содержащие JSON, в строки, содержащие JSON--
Используя map
, мы должны как-то разобраться Exception
. Но как?:
Observable.from(jsonFile).map(new Func1<File, String>() {
@Override public String call(File file) {
try {
return new Gson().toJson(new FileReader(file), Object.class);
} catch (FileNotFoundException e) {
// So Exception. What to do ?
}
return null; // Not good :(
}
});
Используя flatMap
, это намного более многословно, но мы можем переслать проблему по цепочке Observables
и обработать ошибку, если мы выберем другое место и даже повторим попытку:
Observable.from(jsonFile).flatMap(new Func1<File, Observable<String>>() {
@Override public Observable<String> call(final File file) {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override public void call(Subscriber<? super String> subscriber) {
try {
String json = new Gson().toJson(new FileReader(file), Object.class);
subscriber.onNext(json);
subscriber.onCompleted();
} catch (FileNotFoundException e) {
subscriber.onError(e);
}
}
});
}
});
Мне нравится простота map
, но обработка ошибок flatmap
(не многословие). Я не видел каких-либо лучших практик в этой области, и мне любопытно, как это используется на практике.
subscriber.onError()
и т. Д. Все примеры, которые я видел, направляли ошибки таким образом. Это не имеет значения?OnErrorThrowable
являютсяprivate
и вам нужно использоватьOnErrorThrowable.from(e)
вместо этого.FlatMap ведет себя очень похоже на карту, разница в том, что применяемая функция возвращает саму наблюдаемую, поэтому она идеально подходит для отображения асинхронных операций.
В практическом смысле применяемая функция Map просто выполняет преобразование по цепочечному ответу (не возвращая Observable); в то время как функция FlatMap применяет, возвращает
Observable<T>
, поэтому FlatMap рекомендуется, если вы планируете сделать асинхронный вызов внутри метода.Резюме:
Яркий пример можно увидеть здесь: http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk .
Клиент Couchbase Java 2.X использует Rx для предоставления асинхронных вызовов удобным способом. Поскольку он использует Rx, у него есть методы map и FlatMap, объяснение в их документации может быть полезно для понимания общей концепции.
Чтобы обработать ошибки, переопределите onError на своем susbcriber.
Это может помочь посмотреть на этот документ: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
Хороший источник информации об управлении ошибками с помощью RX можно найти по адресу: https://gist.github.com/daschl/db9fcc9d2b932115b679.
источник
В вашем случае вам нужна карта, так как есть только 1 вход и 1 выход.
Предоставленная карта функция просто принимает элемент и возвращает элемент, который будет выпущен дальше (только один раз) вниз.
Предоставленная flatMap функция принимает элемент, а затем возвращает «Observable», то есть каждый элемент нового «Observable» будет излучаться отдельно ниже.
Может быть, код прояснит для вас вещи:
Вывод:
источник
Я думаю о том, что вы используете,
flatMap
когда функция, которую вы хотели поместить внутрь,map()
возвращаетObservable
. В этом случае вы все еще можете попытаться использовать,map()
но это будет непрактично. Позвольте мне попытаться объяснить, почему.Если в таком случае вы решили придерживаться
map
, вы получитеObservable<Observable<Something>>
. Например, в вашем случае, если бы мы использовали воображаемую библиотеку RxGson, которая возвращала методObservable<String>
из своегоtoJson()
метода (вместо простого возврата aString
), это выглядело бы так:На данный момент это было бы довольно сложно
subscribe()
для такой наблюдаемой. Внутри него вы получите то,Observable<String>
к чему вам снова нужноsubscribe()
будет получить значение. Что не практично или приятно смотреть.Таким образом, чтобы сделать его полезным, одна идея состоит в том, чтобы «сгладить» эту наблюдаемую наблюдаемость (вы можете начать видеть, откуда происходит имя _flat_Map). RxJava предоставляет несколько способов сгладить наблюдаемые объекты и для простоты предположим, что объединение - это то, что мы хотим. Слияние в основном берет кучу наблюдаемых и испускает всякий раз, когда любой из них излучает. (Многие люди утверждают, что переключение будет лучшим вариантом по умолчанию. Но если вы используете только одно значение, это не имеет значения.)
Таким образом, изменяя наш предыдущий фрагмент, мы получим:
Это гораздо полезнее, потому что подписавшись на это (или сопоставляя, или фильтруя, или ...), вы просто получаете
String
значение. (Такжеmerge()
обратите внимание, что такой вариант не существует в RxJava, но если вы понимаете идею слияния, то я надеюсь, что вы также поймете, как это будет работать.)Таким образом, в основном потому, что такое,
merge()
вероятно, должно быть полезным только тогда, когда оно успешноmap()
возвращает наблюдаемое, и поэтому вам не нужно вводить это снова и снова, оноflatMap()
было создано как сокращение. Он применяет функцию отображения точно так же, как обычноmap()
, но позже, вместо вывода возвращаемых значений, он также «выравнивает» (или объединяет) их.Это общий случай использования. Это наиболее полезно в кодовой базе, которая использует Rx везде, и у вас есть много методов, возвращающих наблюдаемые, которые вы хотите связать с другими методами, возвращающими наблюдаемые.
В вашем случае это также полезно, потому что
map()
можно преобразовать только одно значение, полученное в,onNext()
в другое значение, полученное вonNext()
. Но это не может преобразовать это в многократные значения, никакое значение вообще или ошибку. И как akarnokd написал в своем ответе (и имейте в виду, что он намного умнее меня, вероятно, в целом, но, по крайней мере, когда речь идет о RxJava), вы не должны выбрасывать исключения из своегоmap()
. Так что вместо этого вы можете использоватьflatMap()
икогда все идет хорошо, но
когда что-то не получается.
Смотрите его ответ для полного фрагмента: https://stackoverflow.com/a/30330772/1402641
источник
Вопрос в том, когда вы используете карту против flatMap в RxJava? , И я думаю, что простая демонстрация более конкретна.
Если вы хотите преобразовать испускаемый элемент в другой тип, в вашем случае конвертация файла в String может сработать как map, так и flatMap. Но я предпочитаю оператор карты, потому что это более понятно.
Однако в каком-то месте,
flatMap
может делать магическую работу, ноmap
не может. Например, я хочу получить информацию о пользователе, но я должен сначала получить его идентификатор при входе пользователя в систему. Очевидно, мне нужны два запроса, и они в порядке.Давай начнем.
Вот два метода: один для входа в систему
Response
, а другой для получения информации о пользователе.Как видите, в функции применяется flatMap, сначала я получаю идентификатор пользователя, а
Response
затем извлекаю информацию о пользователе. Когда два запроса завершены, мы можем выполнить нашу работу, например обновить пользовательский интерфейс или сохранить данные в базе данных.Однако, если вы используете,
map
вы не можете написать такой хороший код. Одним словом,flatMap
может помочь нам сериализовать запросы.источник
Вот простой палец правило , которое я использую помочь мне решить, что и когда использовать
flatMap()
болееmap()
в Rx - хObservable
.Как только вы примете решение использовать
map
преобразование, вы напишите свой код преобразования, чтобы вернуть некоторый объект, верно?Если то, что вы возвращаете в качестве конечного результата вашего преобразования:
ненаблюдаемый объект, то вы бы просто использовали
map()
. Иmap()
оборачивает этот объект в Observable и испускает его.Observable
объект, то вы будете использоватьflatMap()
. ИflatMap()
разворачивает Observable, выбирает возвращенный объект, оборачивает его своим Observable и испускает.Например, у нас есть метод titleCase (String inputParam), который возвращает объект Titled Cased String входного параметра. Тип возврата этого метода может быть
String
илиObservable<String>
.Если бы возвращаемый тип
titleCase(..)
был простымString
, то вы бы использовалиmap(s -> titleCase(s))
Если бы возвращаемый тип
titleCase(..)
былObservable<String>
, то вы бы использовалиflatMap(s -> titleCase(s))
Надеюсь, что это проясняет.
источник
Я просто хотел добавить, что
flatMap
вам не нужно использовать свой собственный Observable внутри функции, и вы можете положиться на стандартные фабричные методы / операторы:Как правило, вам следует избегать создания исключений (Runtime-) из методов onXXX и обратных вызовов, если это возможно, даже несмотря на то, что мы поместили в RxJava столько защитных средств, сколько могли бы.
источник
В этом сценарии используйте карту, вам не нужен новый Observable для нее.
вам следует использовать Exceptions.propagate, который является оберткой, чтобы вы могли отправлять эти проверенные исключения в механизм rx
Затем вы должны обработать эту ошибку в подписчике
Для этого есть отличный пост: http://blog.danlew.net/2015/12/08/error-handling-in-rxjava/
источник
В некоторых случаях вы можете получить цепочку наблюдаемых, в которой ваша наблюдаемая будет возвращать другую наблюдаемую. Вид 'flatmap' разворачивает вторую наблюдаемую информацию, которая скрыта в первой, и позволяет вам непосредственно получить доступ к данным, которые вторая наблюдаемая выделяет при подписке.
источник
Flatmap отображает наблюдаемые в наблюдаемые. Карта сопоставляет элементы с элементами.
Flatmap более гибкая, но Map более легкая и прямая, поэтому она зависит от вашего варианта использования.
Если вы делаете НИЧЕГО асинхронного (включая переключение потоков), вы должны использовать Flatmap, так как Map не будет проверять, находится ли потребитель (часть облегченного доступа)
источник