A maneira como penso sobre isso é que você usa flatMap
quando a função que você deseja colocar dentro de map()
retorna um Observable
. Nesse caso, você ainda pode tentar usar, map()
mas seria impraticável. Deixe-me tentar explicar o porquê.
Se, nesse caso, você decidisse map
continuar, obteria um Observable<Observable<Something>>
. Por exemplo, no seu caso, se usássemos uma biblioteca RxGson imaginária, que retornasse um método Observable<String>
from toJson()
(do que simplesmente retorne a String
), ficaria assim:
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
Neste ponto, seria bastante complicado para subscribe()
um observável. Dentro dele, você obteria um valor Observable<String>
ao qual seria necessário subscribe()
obter novamente o valor. O que não é prático ou agradável de se olhar.
Portanto, para tornar útil uma idéia, é "achatar" esse observável de observáveis (você pode começar a ver de onde vem o nome _flat_Map). O RxJava fornece algumas maneiras de nivelar os observáveis e, por uma questão de simplicidade, vamos assumir que a mesclagem é o que queremos. A mesclagem basicamente pega um monte de observáveis e emite sempre que algum deles é emitido. (Muitas pessoas argumentam que a troca seria um padrão melhor. Mas se você estiver emitindo apenas um valor, isso não importa).
Assim, alterando nosso snippet anterior, obteríamos:
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
Isso é muito mais útil, porque, ao se inscrever nisso (ou mapear, filtrar ou ...), você apenas obtém o String
valor. (Além disso, lembre-se, essa variante de merge()
não existe no RxJava, mas se você entender a idéia de mesclagem, espero que você também entenda como isso funcionaria.)
Então, basicamente porque isso merge()
provavelmente só deve ser útil quando for possível map()
retornar um observável e, assim, você não precisará digitar isso repetidamente, flatMap()
foi criado como uma abreviação. Ele aplica a função de mapeamento da mesma maneira que map()
faria normalmente , mas mais tarde, em vez de emitir os valores retornados, também os "achata" (ou mescla).
Esse é o caso de uso geral. É mais útil em uma base de código que usa Rx em todo o lugar e você tem muitos métodos retornando observáveis, que você deseja encadear com outros métodos retornando observáveis.
Em seu caso de uso ele passa a ser útil também, porque map()
só pode transformar um valor emitido em onNext()
em outro valor emitido em onNext()
. Mas não pode transformá-lo em vários valores, nenhum valor ou um erro. E como o akarnokd escreveu em sua resposta (e lembre-se de que ele é muito mais esperto que eu, provavelmente em geral, mas pelo menos no que diz respeito ao RxJava), você não deve lançar exceções no seu map()
. Então, em vez disso, você pode usar flatMap()
e
return Observable.just(value);
quando tudo vai bem, mas
return Observable.error(exception);
quando algo falha.
Veja sua resposta para obter um trecho completo: https://stackoverflow.com/a/30330772/1402641
subscriber.onError()
etc. Todos os exemplos que eu vi rotearam erros dessa maneira. Isso não importa?