La façon dont je pense les choses est que vous utilisez flatMap
lorsque la fonction que vous vouliez mettre à l'intérieur de map()
renvoie un fichier Observable
. Dans ce cas, vous pourriez toujours essayer d'utiliser map()
mais ce ne serait pas pratique. Laissez-moi essayer d'expliquer pourquoi.
Si dans ce cas vous décidiez de vous en tenir map
, vous obtiendrez un fichier Observable<Observable<Something>>
. Par exemple, dans votre cas, si nous utilisions une bibliothèque RxGson imaginaire, qui retournait une méthode de Observable<String>
sa toJson()
méthode (au lieu de simplement renvoyer a String
), cela ressemblerait à ceci:
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
À ce stade, il serait assez difficile de subscribe()
faire un tel observable. À l'intérieur de celui-ci, vous obtiendrez un Observable<String>
auquel vous auriez à nouveau besoin subscribe()
pour obtenir la valeur. Ce qui n'est ni pratique ni agréable à regarder.
Donc, pour le rendre utile, une idée est d '"aplatir" cette observable d'observables (vous pourriez commencer à voir d'où vient le nom _flat_Map). RxJava fournit quelques moyens d'aplatir les observables et, par souci de simplicité, supposons que la fusion est ce que nous voulons. Merge prend essentiellement un tas d'observables et émet chaque fois que l'un d'eux émet. (Beaucoup de gens diraient que le commutateur serait une meilleure valeur par défaut. Mais si vous n'émettez qu'une seule valeur, cela n'a pas d'importance de toute façon.)
Donc, en modifiant notre extrait de code précédent, nous obtiendrions:
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
C'est beaucoup plus utile, car en vous abonnant à cela (ou en mappant, ou en filtrant, ou ...) vous obtenez juste la String
valeur. (De plus, merge()
remarquez qu'une telle variante de n'existe pas dans RxJava, mais si vous comprenez l'idée de fusion, j'espère que vous comprenez également comment cela fonctionnerait.)
Donc, fondamentalement, parce que tel merge()
ne devrait probablement jamais être utile que quand il réussit à map()
renvoyer un observable et que vous n'avez donc pas à le taper encore et encore, a flatMap()
été créé comme un raccourci. Il applique la fonction de mappage comme d'habitude map()
, mais plus tard, au lieu d'émettre les valeurs renvoyées, il les "aplatit" (ou les fusionne).
C'est le cas d'utilisation général. C'est très utile dans une base de code qui utilise Rx partout et vous avez de nombreuses méthodes renvoyant des observables, que vous souhaitez enchaîner avec d'autres méthodes renvoyant des observables.
Dans votre cas d'utilisation, cela s'avère également utile, car map()
vous ne pouvez transformer qu'une valeur émise onNext()
dans une autre valeur émise dans onNext()
. Mais il ne peut pas le transformer en plusieurs valeurs, aucune valeur du tout ou une erreur. Et comme akarnokd l'a écrit dans sa réponse (et attention, il est beaucoup plus intelligent que moi, probablement en général, mais au moins quand il s'agit de RxJava), vous ne devriez pas jeter d'exceptions à votre map()
. Donc à la place, vous pouvez utiliser flatMap()
et
return Observable.just(value);
quand tout va bien, mais
return Observable.error(exception);
quand quelque chose échoue.
Voir sa réponse pour un extrait complet: https://stackoverflow.com/a/30330772/1402641
subscriber.onError()
etc. Tous les exemples que j'ai vus ont acheminé des erreurs de cette façon. Cela n'a pas d'importance?