Los operadores se utilizan para resolver el problema de transformar objetos observables. Los operadores se utilizan para modificar eventos emitidos por observables entre el suscriptor observable y el final. RXJAVA proporciona muchos operadores útiles.
Por ejemplo, el operador del mapa se usa para convertir un evento en otro.
Observable.just ("¡Hello, World!") .Map (new Func1 <String, String> () {@Override public String Call (String S) {return s + "-dan";}}) .subscribe (s -> system.out.println (s)); Usar lambda se puede simplificar para
Observable.just ("¡Hola, mundo!") .Map (s -> s + "-dan") .subscribe (s -> system.out.println (s));¿No es genial? El operador MAP () se usa para transformar el objeto observable. El operador del mapa devuelve un objeto observable, de modo que se pueda implementar una llamada en cadena, y el operador del mapa se usa varias veces en un objeto observable, y finalmente los datos más simples se pasan al objeto de suscriptor.
Operador de mapa avanzado
Lo que es más interesante del operador del mapa es que no tiene que devolver el tipo devuelto por el objeto observable. Puede usar el operador de mapa para devolver un objeto observable que emite el nuevo tipo de datos.
Por ejemplo, en el ejemplo anterior, el suscriptor no le importa la cadena devuelta, pero quiere el valor hash de la cadena.
Observable.just ("¡Hello, World!") .Map (new Func1 <String, Integer> () {@Override public Integer Call (String S) {return s.hashcode ();}}) .subscribe (i -> system.out.println (integer.ToString (i))); Muy interesante, ¿verdad? Nuestro observable inicial devuelve una cadena, mientras que el suscriptor final recibe un entero. Por supuesto, usar Lambda puede simplificar aún más el código:
Observable.just ("¡Hola, mundo!") .Map (s -> s.hashcode ()) .subscribe (i -> system.out.println (integer.ToString (i))); Como se mencionó anteriormente, cuanto menos se suscriban las cosas, mejor. Agreguemos otro operador de mapa.
Observable.just ("¡Hola, mundo!") .Map (s -> s.hashcode ()) .map (i -> integer.ToString (i)) .subscribe (s -> system.out.println (s)); No convencido?
¿Crees que nuestro ejemplo es demasiado simple para convencerte? Necesitas entender los siguientes dos puntos:
1. Observable y suscriptor puede hacer cualquier cosa
Observable puede ser una consulta de base de datos, y el suscriptor se usa para mostrar los resultados de la consulta; Observable puede ser un evento de clic en la pantalla, y el suscriptor se utiliza para responder a los eventos de clic; Observable puede ser una solicitud de red, y el suscriptor se utiliza para mostrar los resultados de la solicitud.
2. Observable y suscriptor son independientes del proceso de transformación intermedia.
Se puede agregar o disminuir cualquier número de mapas entre observables y suscriptores. Todo el sistema es altamente combinable, y los datos operativos son un proceso muy simple.
Ejemplo
1. Preparación
Supongamos que tengo un método como este:
Este método devuelve la lista de URL de un sitio web en función de la cadena de entrada (ahha, motor de búsqueda)
Observable <List <String>> Query (texto de cadena);
Ahora quiero construir un sistema robusto que pueda consultar cadenas y mostrar los resultados. Según el contenido del blog anterior, podemos escribir el siguiente código:
consulta ("¡Hola, mundo!") .Subscribe (urls -> {for (string url: urls) {system.out.println (url);}});Por supuesto, este tipo de código no se puede tolerar, porque el código anterior nos ha hecho perder la capacidad de cambiar el flujo de datos. Una vez que queremos cambiar cada URL, solo podemos hacerlo en suscriptor. ¡No usamos un operador de mapa () tan genial! ! !
Por supuesto, puedo usar el operador del mapa. La entrada del mapa es la lista de URLS. Al procesar, todavía necesita atravesar cada uno, lo cual también es muy doloroso.
Afortunadamente, también está el método observable.from (), que recibe una colección como entrada y luego genera un elemento al suscriptor a la vez:
Observable.from ("url1", "url2", "url3") .subscribe (url -> system.out.println (url)); Usemos este método para la escena justo ahora:
consulta ("¡Hola, mundo!") .Subscribe (urls -> {observable.from (urls) .subscribe (url -> system.out.println (url));});
Aunque se elimina para cada bucle, el código todavía se ve desordenado. Múltiples suscripciones anidadas no solo se ven feas y difíciles de modificar, sino que más en serio, destruirá algunas de las características de Rxjava que aún no hemos mencionado.
2. Mejora
El Salvador está aquí, él es FlatMap ().
Observable.flatMap () recibe la salida de un observable como entrada y sale otra observable al mismo tiempo. Mire directamente el código:
QUERY ("¡Hola, Mundo!") .flatmap (nuevo func1 <list <string>, observable <string>> () {@Override public observable <string> call (list <String> urls) {return observable.from (urls);}}) .subscrite (url -> system.println (url)); Aquí publiqué todo el código de funciones para facilitarle que comprenda lo que está sucediendo. El uso de Lambda puede simplificar enormemente la longitud del código:
consulta ("¡Hola, mundo!") .flatmap (urls -> observable.from (urls)) .subscribe (url -> system.out.println (url));¿FlatMap () se ve raro? ¿Por qué devuelve otro observable? El punto clave para comprender FlatMap es que la nueva salida observable de FlatMap es exactamente lo que queremos recibir en suscriptor. Ahora, el suscriptor ya no recibe List <String>, sino que recibe algunas cadenas individuales de columnas, al igual que la salida de observable.from ().
Esta parte también es la parte más difícil cuando aprendí por primera vez rxjava. Una vez que de repente me di cuenta, muchas de las preguntas en Rxjava se resolvieron.
3. Puede ser mejor
FlatMap () realmente no es una mejor idea, puede devolver cualquier objeto observable que desee devolver.
Por ejemplo, el siguiente método:
// Devuelve el título del sitio web, y si es 404, devuelve nulo observable <string> getTitle (url de cadena);
Siguiendo el ejemplo anterior, ahora ya no quiero imprimir la URL, sino imprimir el título de cada sitio web que recibo. El problema es que mi método solo puede pasar en una URL a la vez, y el valor de retorno no es una cadena, sino un objeto observable que genera una cadena. Usar FlatMap () simplemente puede resolver este problema.
Query ("¡Hola, Mundo!") .flatmap (urls -> observable.from (urls)) .flatmap (new Func1 <String, Observable <String> () {@Override Public Observable <String> call (String Url) {return getTitle (url);}} .subscribe (title -> system.println (title (title (title (title (title (titleNnn); 4. Use lambda:
consulta ("¡Hola, mundo!") .flatmap (urls -> observable.from (urls)) .flatmap (url -> gettitle (url)) .subscribe (title -> system.println (title)); ¿No se siente increíble? ¡De hecho, puedo combinar múltiples métodos independientes para devolver objetos observables juntos! ¡Muy guapo!
Más que eso, también combiné las llamadas de dos API en una llamada encadenada. Podemos vincular tantas llamadas API tantas como sea posible. Todos deben saber lo doloroso que es sincronizar todas las llamadas de API y luego combinar los resultados de la devolución de llamada de todas las llamadas de API en los datos que se mostrarán. Aquí evitamos con éxito el infierno de devolución de llamada (devoluciones de llamada anidadas de múltiples capas, lo que hace que el código sea difícil de leer y mantener). Ahora toda la lógica está envuelta en esta simple llamada receptiva.
5. Operadores ricos <Br /> Hasta ahora, hemos entrado en contacto con dos operadores, y hay más operadores en RXJAVA, entonces, ¿cómo usamos otros operadores para mejorar nuestro código?
getTitle () Devuelve nulo si la URL no existe. ¡No queremos emitir "NULL", luego podemos filtrar el valor nulo de la lista de títulos devuelta!
consulta ("¡Hola, mundo!") .flatmap (urls -> observable.from (urls)) .flatmap (url -> gettitle (url)) .filter (title -> title! = null) .subscribe (title -> system.out.println (title));Filter () emite los mismos elementos que la entrada y filtra aquellos que no cumplen con los criterios de verificación.
Si solo queremos hasta 5 resultados:
consulta ("¡Hola, mundo!") .flatmap (urls -> observable.from (urls)) .flatmap (url -> gettitle (url)) .filter (title -> title! = null) .take (5) .subscribe (title -> system.println (title));Take () emite el número máximo de resultados.
Si queremos guardar cada título en el disco antes de imprimir:
Query ("¡Hola, Mundo!") .flatmap (urls -> observable.from (urls)) .flatmap (url -> gettitle (url)) .filter (title -> title! = null) .take (5) .doonnext (title -> savetitle (title)) .subscribe (title -> system.println (tithprintln (titular (titular);DoonNext () nos permite hacer algunas cosas adicionales antes de generar un elemento a la vez, como guardar el título aquí.
¿Es fácil ver lo fácil que es operar el flujo de datos aquí? Puede agregar tantas operaciones como desee y no estropear su código.
RXJAVA contiene una gran cantidad de operadores. El número de operadores da un poco de miedo, pero vale la pena revisar uno por uno para que pueda saber qué operadores se pueden usar. Puede tomar algún tiempo comprender a estos operadores, pero una vez que comprenda, comprenderá completamente el poder de Rxjava.
¡Incluso puedes escribir operadores personalizados! Este blog no tiene la intención de personalizar el operador. Si lo desea, por favor, busque en Google usted mismo.
¿Cómo te sientes?
Bueno, eres escéptico y es difícil convencer, entonces, ¿por qué te preocupas por estos operadores?
Porque los operadores le permiten hacer cualquier cosa al flujo de datos.
Vinculación de una serie de operadores puede lograr una lógica compleja. El código se divide en una serie de fragmentos que se pueden combinar. Este es el encanto de la programación de funciones reactivas. Cuanto más lo use, más cambiará su pensamiento de programación.
Además, RXJAVA también nos facilita procesar datos. En el último ejemplo, llamamos a dos API, procesamos los datos devueltos por la API y los guardamos en el disco. Pero nuestro suscriptor no sabe esto, solo piensa que está recibiendo un objeto <string> observable. ¡Un buen embalaje también trae conveniencia de codificación!
En la tercera parte, presentaré algunas otras características interesantes de RXJAVA, como el manejo de errores y la concurrencia, que no se utilizan directamente para procesar datos.