Sposób, w jaki myślę o tym, to użycie flatMap
, gdy funkcja, którą chcesz umieścić wewnątrz map()
zwraca Observable
. W takim przypadku możesz nadal próbować używać map()
, ale byłoby to niepraktyczne. Pozwól mi spróbować wyjaśnić, dlaczego.
Jeśli w takim przypadku zdecydujesz się trzymać z numerem map
, otrzymasz numer Observable<Observable<Something>>
. Na przykład w przypadku, jeśli użyliśmy wyimaginowanej biblioteki RxGson, że zwrócił Observable<String>
od niego znajduje toJson()
sposób (zamiast po prostu zwrócenie String
) to będzie wyglądać następująco:
Observable.from(jsonFile).map(new Func1<File, Observable<String>>() {
@Override public Observable<String>> call(File file) {
return new RxGson().toJson(new FileReader(file), Object.class);
}
}); // you get Observable<Observable<String>> here
W tym momencie byłoby dość podstępny do subscribe()
do takiego obserwowalnego. Wewnątrz tego dostaniesz Observable<String>
, do którego znowu będziesz potrzebował subscribe()
, aby uzyskać wartość. Co nie jest praktyczne ani przyjemne do obejrzenia.
Jednym z pomysłów jest "spłaszczenie" tego obserwowalnego obserwatorium (możesz zacząć widzieć, skąd pochodzi nazwa _flat_Map). RxJava oferuje kilka sposobów na spłaszczanie obserwowalnych obiektów, a dla uproszczenia pozwala założyć, że chcemy uzyskać merge. Merge w zasadzie bierze kilka obserwowalnych i emituje, gdy tylko którykolwiek z nich emituje. (Wielu ludzi twierdzą switch byłby lepszy domyślny Ale jeśli emitując tylko jedną wartość, to i tak nie ma znaczenia.).
Więc zmieniające nasz poprzedni fragment chcemy uzyskać:
Observable.from(jsonFile).map(new Func1<File, Observable<String>>() {
@Override public Observable<String>> call(File file) {
return new RxGson().toJson(new FileReader(file), Object.class);
}
}).merge(); // you get Observable<String> here
Jest to o wiele bardziej przydatne, ponieważ subskrybowanie tego (lub mapowanie, lub filtrowanie, lub ...) po prostu uzyskać wartość String
. (Również, pamiętajcie, taki wariant merge()
nie istnieje w RxJava, ale jeśli zrozumieć ideę scalenia potem mam nadzieję, że również zrozumieć, jak to będzie działać.)
Więc w zasadzie, bo takie merge()
prawdopodobnie powinien być tylko użyteczne, gdy powodzi się map()
zwracając obserwowalne i dlatego nie trzeba wpisywać tego w kółko, flatMap()
został stworzony jako skrót. Wykorzystuje funkcję odwzorowania tak, jak normalnie, ale później zamiast emitować zwrócone wartości, również "spłaszcza" je (lub je scala).
To ogólny przypadek użycia. Jest to najbardziej przydatne w kodzie źródłowym, które używa Rx allover to miejsce i masz wiele metod zwracających obserwowalne, które chcesz połączyć z innymi metodami zwracającymi obserwowalne.
W przypadku użycia okazało się również przydatne, ponieważ map()
może przekształcić tylko jedną wartość emitowaną w onNext()
na inną wartość emitowaną w onNext()
. Ale nie może przekształcić go w wiele wartości, żadnej wartości ani błędu. I jak napisał akarnokd w swojej odpowiedzi (i uważam, że jest o wiele mądrzejszy ode mnie, prawdopodobnie w ogóle, ale przynajmniej jeśli chodzi o RxJava) nie powinieneś wyrzucać wyjątków z twojego map()
. Zamiast więc można używać flatMap()
i
return Observable.just(value);
gdy wszystko idzie dobrze, ale
return Observable.error(exception);
gdy coś się nie powiedzie.
Zobacz jego odpowiedź dla pełnego urywek: https://stackoverflow.com/a/30330772/1402641
To nie wywołuje 'subscriber.onError()' itd. Wszystkie przykłady, które widziałem, przekierowywały błędy w ten sposób. Czy to nie ma znaczenia? –
Należy zauważyć, że konstruktory 'OnErrorThrowable' są' prywatne' i zamiast tego należy użyć 'OnErrorThrowable.from (e)'. –
Właśnie zaktualizowałem. OnErrorThrowable.from (e) nie zachowuje wartości, więc korzystam z OnErrorThrowable.addValueAsLastCause (e, file), która powinna zachować wartość. – dwursteisen