Soy nuevo en RXJava/RXAndroid. Quiero implementar este caso: elegí una forma diferente según alguna condición en RXJava. Por ejemplo, primero, obtengo la información del usuario de la red y, si se trata de un usuario VIP, obtendré más información de la red o simplemente mostraré información en el hilo principal (romper la cadena). Aquí el diagrama de flujo: https: //i.stack.imgur.com/0hztR.png
Hago una búsqueda sobre esto y solo encuentro que "switchIfEmpty" puede ayudar. Escribo el siguiente código:
getUserFromNetwork("userId") .flatMap(new Function<User, ObservableSource<User>>() { @Override public ObservableSource<User> apply(User user) throws Exception { if(!user.isVip){ //show user info on MainThread! return Observable.empty(); }else{ return getVipUserFromNetwork("userId"); } } }).switchIfEmpty(new ObservableSource<User>() { @Override public void subscribe(Observer<? super User> observer) { //show user info in main thread //just break the chain for normal user observer.onComplete(); } }).doOnNext(new Consumer<User>() { @Override public void accept(User user) throws Exception { //show vip user info in main thread } }).subscribe();¿Hay una manera más simple de lograr esto?
¡Gracias!
flatMap() es una buena opción, puede dividir el flujo con él, pero al final el flujo se fusiona (todas las emisiones de cada flujo observable dividido hacia el flujo principal). En su código, switchIfEmpty() es redundante ya que eso es exactamente lo que hace Observable.empty() (invoque inmediatamente onCompleted() ), y también necesita, por supuesto, observe on, si desea que la visualización ocurra en el hilo principal, pero de todos modos, creo que no es una buena práctica manejar esto en medio de la corriente.
Creo que en su caso, puede manejar (reaccionar a) la emisión del usuario en un solo controlador, ya que es muy similar, solo verifique si es VIP o no y muéstrelo en consecuencia. por lo que debería verse algo como esto:
getUserFromNetwork("userId") .flatMap(new Function<User, ObservableSource<User>>() { @Override public ObservableSource<User> apply(User user) throws Exception { if (!user.isVip) { return Observable.just(user); } else { return getVipUserFromNetwork("userId"); } } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(user -> { if (user.isVip){ //display vip user }else{ //display regular user } });en este enfoque, tiene un flujo de corriente único, sin 'efectos secundarios' en el medio de la corriente.
En caso de que esté manejando es totalmente diferente (que no es este caso), entonces puede dividir la transmisión en 2 transmisiones separadas y reaccionar a cada una de manera diferente, esto se puede hacer mediante la multidifusión de su Observable getUserFromNetwork() , y desde este Observable cree 2 Observable diferentes, uno que continuará, por ejemplo, getVipUserFromNetwork() , y otro que no, y cada uno puede tener una lógica de suscriptor diferente. (puedes leer aquí mi respuesta con respecto a la multidifusión)
Recientemente descubrí el operador switchIfEmpty , que se adaptaba a mis necesidades y puede ser útil para algunos. Rx sigue siendo una nueva forma de pensar para mí, por lo que también estoy abierto a sugerencias y comentarios. Déjame tratar de darte otra forma de pensar sobre esto. Como señaló @yosriz, usar switchIfEmpty con un onComplete posterior es redundante.
Como dice el nombre, switchIfEmpty cambia a otro observable cuando el base se completa sin emitir ningún valor.
Estos son los 2 casos:
El truco consiste en utilizar un flujo vacío como predicado.
Dado un observable base utilizado como predicado, si filtra su emisión, puede encadenar un operador switchIfEmpty a su flujo de respaldo.
En el siguiente código, "Usuario" y "Usuario VIP" comparten la misma interfaz/clase. Incluso si estoy usando Java 8 Lambdas para escribir el código, observe que no hay declaraciones IF .
// User Observable, cached so only 1 network call is done Observable<User> user = getUserFromNetwork("USER_ID").cache(); // This observable is the user's VIP Status as a boolean stream Observable<Boolean> isVip = user.map(u -> u.isVip() );Luego hacemos un poco de lógica, pasamos el valor de isVip hacia abajo cuando es un VIP, si el usuario no es un VIP, el flatMap no se evaluará.
Observable<User> vipUser = isVip // If VIP emit downstream .filter(vip -> vip) // This flatmap is ignored if // the emission is filtered out ( vip -> vip == false ) .flatMap(vip -> user.flatMap(usr -> { return getVipUserFromNetwork(usr.getId()); })); });En este punto, el vipUser observable puede
Cuando no se emite nada, switchIfEmpty llamará al otro observable
vipUser.switchIfEmpty(user) .observeOn(AndroidSchedulers.mainThread()) .subscribe(usr -> { // Logging the class just to understand the outcome System.out.println("User instanceOf " + usr.getClass()); });Aquí está el código completo
Observable<User> user = getUserFromNetwork("USER_ID").cache(); Observable<Boolean> isVip = user.map(u -> u.isVip() ); Observable<User> vipUser = isVip .filter(vip -> vip) .flatMap(vip -> user.flatMap(usr -> { return getVipUserFromNetwork(usr.getId()); })); }); vipUser.switchIfEmpty(user) .observeOn(AndroidSchedulers.mainThread()) .subscribe(usr -> { // Handle UI Changes });