Myślę o tym, że używasz, flatMap
gdy funkcja, którą chcesz wstawić, map()
zwraca Observable
. W takim przypadku nadal możesz spróbować użyć, map()
ale byłoby to niepraktyczne. Pozwól, że wyjaśnię dlaczego.
Jeśli w takim przypadku zdecydujesz się trzymać map
, dostaniesz Observable<Observable<Something>>
. Na przykład w twoim przypadku, gdybyśmy użyli wyimaginowanej biblioteki RxGson, która zwróciła metodę Observable<String>
z jej toJson()
metody (zamiast po prostu String
zwrócić a ), wyglądałaby 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ść trudne subscribe()
do takiego obserwowalnego. Wewnątrz dostaniesz coś, Observable<String>
do czego będziesz musiał ponownie subscribe()
uzyskać wartość. Które nie jest praktyczne ani przyjemne dla oka.
Aby uczynić to użytecznym, jednym z pomysłów jest „spłaszczenie” tego, co można zaobserwować (można zacząć widzieć, skąd pochodzi nazwa _flat_Map). RxJava oferuje kilka sposobów spłaszczania obserwowalnych i dla uproszczenia załóżmy, że scalenie jest tym, czego chcemy. Scalanie zajmuje zasadniczo kilka obserwowalnych i emituje za każdym razem, gdy emituje którekolwiek z nich. (Wiele osób twierdzi, że zmiana byłaby lepszym rozwiązaniem domyślnym. Ale jeśli emitujesz tylko jedną wartość, to i tak nie ma znaczenia.)
Tak więc zmieniając nasz poprzedni fragment otrzymamy:
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ż subskrybując to (lub mapując, filtrując lub ...) po prostu dostajesz String
wartość. (Również pamiętać, taki wariant merge()
nie istnieje w RxJava, ale jeśli rozumiesz ideę scalenia, to mam nadzieję, że rozumiesz również, jak to by działało).
Zasadniczo dlatego, że takie merge()
powinny być prawdopodobnie użyteczne tylko wtedy, gdy uda się zwrócić map()
obserwowalny, a więc nie trzeba wpisywać tego w kółko, flatMap()
został stworzony jako skrót. Stosuje funkcję mapowania tak jak normalnie map()
, ale później zamiast emitować zwracane wartości, „spłaszcza” je (lub scala).
To ogólny przypadek użycia. Jest to najbardziej przydatne w bazie kodu, która używa Rx w całym miejscu i masz wiele metod zwracających obserwowalne, które chcesz połączyć z innymi metodami zwracającymi obserwowalne.
W twoim przypadku jest to również przydatne, ponieważ map()
może przekształcić tylko jedną emitowaną wartość w onNext()
inną emitowaną wartość onNext()
. Ale nie może przekształcić go w wiele wartości, żadnej wartości lub błędu. I jak napisał akarnokd w swojej odpowiedzi (i pamiętaj, że jest znacznie mądrzejszy ode mnie, prawdopodobnie ogólnie, ale przynajmniej jeśli chodzi o RxJava), nie powinieneś rzucać wyjątków od siebie map()
. Zamiast tego możesz użyć flatMap()
i
return Observable.just(value);
kiedy wszystko idzie dobrze, ale
return Observable.error(exception);
kiedy coś zawiedzie.
Zobacz jego odpowiedź na pełny fragment: https://stackoverflow.com/a/30330772/1402641
subscriber.onError()
itd. Wszystkie przykłady, które widziałem, spowodowały błędy w ten sposób. Czy to nie ma znaczenia?