Programación
Reactiva en Android

Oier Blasco Linares !
@oier!
Diciembre 2013
Contenido
•

Limitaciones de los componentes android.!

•

Introducción a RxJava.!

•

Concurrencia.!

•

Pros y Contras.!

•

Preguntas.
Limitaciones de los componentes Android
Intent Service

•

No especifica como notificar a los clientes.!

•

Ningún controlo sobre la concurrencia.!

•

No especifican método de gestión de errores.
AsyncTask

•

Implementación cambia dependiendo del la version de android.!

•

En la version actual se ejecutan en serie.!

•

Suelen ser fuente de context leak.!

•

No especifican método de gestión de errores/excepciones.
Programación reactiva
Programación reativa
Definición

“La programación reactiva es un paradigma de
programación orientado a flujos de datos y a la
propagación de cambios. “ Wikipedia
Programación imperativa
ejemplo

X = 10;!
y = x + 5;!
X= 20!
Cual es el valor de Y? 15
Programación reactiva
ejemplo

X = 10;!
Func<int> y = () -> {x + 5};!
X= 20!
Cual es el valor de Y? 25
RX JAVA
RxJava
•

Una librería para componer programas asíncronos y
basados en evento mediante el uso de secuencias
observables.!

•

Open source.!

•

Creada por Netflix.!

•

Un port de “Reactive extension” creadas por Microsoft.!

•

Observable / Observer como elementos basicos.
Observable
•

Una secuencia de valores , finita o infinita.!

•

Permite la subscripción de observer mediante el método
subscribe.!

•

Lazy evaluation.!
Observer
•

Extension del patron observer de GoF.!

•

Se subscribe a objectos que implemente el interfaz
Observable y reacciona a lo items que este emita.!

•

El observer “espera” de manera no bloquean los valores
emitidos por el Observable.!
!
Observer
Observer<String>

stringObserver = new Observer<String> {	

!

public void onNext(String value) {	
	System.out.println(“ NextValue : ” + value);	
}	
public void onCompleted() {	
	System.out.println(“Done!”);	
}	
public void onError(Throwable t) { 	
		 System.out.println(“ERROR!!!!!”);	
}	 	
}
Observable
Observable.create( new Observable.OnSubscribeFunc<String>() {	
!

public Subscription onSubscribe(Observer<? super String> observer) {	
	
	 	 	
observer.onNext("pedro@domain.com");	
observer.onNext("maria@domain.com");	
observer.onNext("juan@domain.com");	
observer.onNext("isa@domain.com");	
!

observer.onCompleted();	
!

return Subscriptions.empty();	
}	
!

});
Composición
Composición
•

Los Observables pueden modificados mediante operadores.!

•

Estos operadores permiten filtrar , combinar y transformar las
secuencias representadas por los Observables.!

•

Los operadores retornan otros observables con lo cual se pueden
concatenar para producir la secuencia de datos deseada.!

•

RxJava viene con más de 50 operadores.!

•

Es posible crear mas operadores para ajustarlos a nuestras necesidades.!

•

Los “Marble diagrams” se usan en la documentación de RxJava para
explicar el funcionamiento de los operadores de una forma gráfica. !
Observer de ejemplo
private static Observer<Integer> createIntegerObserver(){	
	 return new Observer<Integer>() {	
!

public void onCompleted() {	
	 System.out.println("Sequence complete");	
}	
!

	
	

public void onError(Throwable throwable) {	
	 String msg = throwable.getMessage();
	 	 System.out.println("Error: “+ msg);	
}	

!

public void onNext(Integer i) {	
	 	 System.out.println(i)	
	
}	
};	
}
Map

Transforma la secuencia mediante la función
Integer[] values = new Integer[]{1, 2, 3, 4, 5};	
Observable<Integer> numbers = Observable.from(values);	
!
numbers.map(new Func1<Integer, Integer>() {	
public Integer call(Integer i) {	
return i * i;	
}	
}).subscribe(observer);

Output:

1!
4!
9!
16!
25!
MapMany

Combina n secuencias mediante la función
Observable<String> myStockSymbols =
StocksService.myPortfolio();	
Observer<StockInfo> stockInfoObserver = createStockInfoObserver();	

!
myStockSymbols.mapMany(new Func1<String, Observable<StockInfo>>() {	
	
public Observable<StockInfo> call(String stockSymbol) {	
return StocksService.getLastQuotes(stockSymbol);	
}	

!
}).subscribe(stockInfoObserver);

Output:

[AAPL-> 25,730120]!
[GOOG -> 23,464752]!
[GOOG -> 11,255009]!
Sequence complete
Reduce

Aplica una función a cada item devolviendo únicamente el acumulado
Integer[] values = new Integer[]{1, 2, 3, 4, 5};	
Observable<Integer> numbers = Observable.from(values);	
Observer<Integer> observer = createIntegerObserver();	

!
numbers.reduce(new Func2<Integer, Integer, Integer>() {	
public Integer call(Integer a , Integer b) {	
return a + b;	
}	
}).subscribe(observer);

Output:

15!
Sequence
complete
Filter

Filtra la secuencia en base a la función suministrada
Integer[] values = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9};	
Observable<Integer> numbers = Observable.from(values);	
Observer<Integer> observer = createIntegerObserver();	

!
numbers.filter(new Func1<Integer, Boolean>() {	
public Boolean call(Integer i) {	
return (i % 2 == 0);	
}	
}).subscribe(observer);

Output:

2!
4!
6!
8!
Sequence complete
SkipWhile

No emite los valores hasta que una condición se cumple
Integer[] values = new Integer[]{1, 2, 3, 4, 5, 4, 3, 2, 1};
Observable<Integer> numbers = Observable.from(values);	

	

!
Observer<Integer> observer = createIntegerObserver();	
numbers.skipWhile(new Func1<Integer, Boolean>() {	
public Boolean call(Integer i) {	
return (i <4);	
}	
}).subscribe(observer);

Output:

4!
5!
4!
3!
2!
1!
Sequence complete
Take

Emite solo los N elementos de la lista
Integer[] values = new Integer[]{1, 2, 3, 4, 5, 4, 3,
2, 1};
	
Observable<Integer> numbers =
Observable.from(values);	
!
Observer<Integer> observer = createIntegerObserver();	
numbers.take(2).subscribe(observer);

Output:

1!
2!
Sequence complete
Distinct

Elimina los duplicados de la secuencia

Integer[] values = new Integer[]{1, 2, 1, 2, 3, 3, 4, 1, 2};	
Observable<Integer> numbers = Observable.from(values);	
Observer<Integer> observer =createIntegerObserver();	

!
numbers.distinct().subscribe(observer);

Output:

1!
2!
3!
4!
Sequence complete
Merge

Fusiona n secuencias
Observable<Integer> odds =	
	
	
Observable.from(new Integer[]{1, 3, 5, 7});	
Observable<Integer> evens = 	
	
	
Observable.from(new Integer[]{2,4,6});	
	
Observer<Integer> observer = createIntegerObserver();	
Observable.merge(odds,evens).subscribe(observer);

Output:

1!
3!
2!
5!
4!
7!
6!
Sequence complete
Zip

Combina n secuencias mediante la función

!

Observable<Integer> odds = Observable.from(new Integer[]{1, 3, 5, 7});	
Observable<Integer> evens = Observable.from(new Integer[]{2,4,6});	
Observer<String> observer = createStringObserver();	
	
Observable.zip(odds,evens ,new Func2<Integer, Integer, String>() {	
	
public String call(Integer a, Integer b) {	
return String.format("[%s,%s]",a,b);	
}	
}).subscribe(observer);	

Output:

[1, 2]!
[3, 4]!
[5, 6]!
Sequence complete
Concurrencia
Schedulers
•

Los observables son mono hilo (single threaded) por defecto.!

•

Los scheduler se usan para introducir la concurrencia permitiendo ejecutar
partes de nuestro cadena de observables concurrentemente.!

•

Hay dos aspectos de nuestros Observables de los que queremos poder
controlar la concurrencia:!
•

•

•

En la invocación de la subscripción. Para ello usaremos el método
Observable.observeOn(Scheduler s).!
En las notificaciones al Observer. Para ello usaremos el método
Observable.notifyOn(Scheduler s).!

Hay varia implementaciones de los schedulers. Ex:
CurrentThreadScheduler, ExecutorScheduler, NewThreadScheduler, …
Schedulers - Ejemplo
public class WeatherAPI	
!

public static Observable<WeatherData> getWeatherFromCities(String ... cities){	
return Observable.from(cities).map(new Func1<String,WeatherData>() {	
public WeatherData call(String s) {	
	

	

	

	
	

	

// Call to remote api	
return RemoteService.getWeatherData(s); 	
}	

}).subscribeOn(Schedulers.threadPoolForIO());	
}	
}
Schedulers - Ejemplo
String [] cities= { "Madrid","Barcelona","Bilbao"} ;
WeatherAPI.getWeatherFromCities(cities) 	
	 .observeOn(AndroidSchedulers.mainThread()) 	
	 .subscribe(new Observer<WeatherData>() {	
	
	

// Safe to call UI code from here	
public void onCompleted() { … }	
public void onError(Throwable throwable) { … }	
public void onNext(String s) {

}});

… }
Pros
•

Método simple y uniforme de tratar los eventos y los
errores (onNext, onError,onCompleted).!

•

Podemos crea APIS que mantengan el control sobre la
concurrencia .!

•

Facilmente Testeable.!

•

Reusable permite que el cliente extienda/adapte la
secuencia usando los operadores.!
Contras

•

Curva de aprendizaje.!

•

Sintaxis de java 6 ( Java 8 lo mejora pero no esta
disponible para programación en android).

Programación Reactiva en Android

  • 1.
    Programación Reactiva en Android OierBlasco Linares ! @oier! Diciembre 2013
  • 2.
    Contenido • Limitaciones de loscomponentes android.! • Introducción a RxJava.! • Concurrencia.! • Pros y Contras.! • Preguntas.
  • 3.
    Limitaciones de loscomponentes Android
  • 4.
    Intent Service • No especificacomo notificar a los clientes.! • Ningún controlo sobre la concurrencia.! • No especifican método de gestión de errores.
  • 5.
    AsyncTask • Implementación cambia dependiendodel la version de android.! • En la version actual se ejecutan en serie.! • Suelen ser fuente de context leak.! • No especifican método de gestión de errores/excepciones.
  • 6.
  • 7.
    Programación reativa Definición “La programaciónreactiva es un paradigma de programación orientado a flujos de datos y a la propagación de cambios. “ Wikipedia
  • 8.
    Programación imperativa ejemplo X =10;! y = x + 5;! X= 20! Cual es el valor de Y? 15
  • 9.
    Programación reactiva ejemplo X =10;! Func<int> y = () -> {x + 5};! X= 20! Cual es el valor de Y? 25
  • 10.
  • 11.
    RxJava • Una librería paracomponer programas asíncronos y basados en evento mediante el uso de secuencias observables.! • Open source.! • Creada por Netflix.! • Un port de “Reactive extension” creadas por Microsoft.! • Observable / Observer como elementos basicos.
  • 12.
    Observable • Una secuencia devalores , finita o infinita.! • Permite la subscripción de observer mediante el método subscribe.! • Lazy evaluation.!
  • 13.
    Observer • Extension del patronobserver de GoF.! • Se subscribe a objectos que implemente el interfaz Observable y reacciona a lo items que este emita.! • El observer “espera” de manera no bloquean los valores emitidos por el Observable.! !
  • 14.
    Observer Observer<String> stringObserver = newObserver<String> { ! public void onNext(String value) { System.out.println(“ NextValue : ” + value); } public void onCompleted() { System.out.println(“Done!”); } public void onError(Throwable t) { System.out.println(“ERROR!!!!!”); } }
  • 15.
    Observable Observable.create( new Observable.OnSubscribeFunc<String>(){ ! public Subscription onSubscribe(Observer<? super String> observer) { observer.onNext("pedro@domain.com"); observer.onNext("maria@domain.com"); observer.onNext("juan@domain.com"); observer.onNext("isa@domain.com"); ! observer.onCompleted(); ! return Subscriptions.empty(); } ! });
  • 16.
  • 17.
    Composición • Los Observables puedenmodificados mediante operadores.! • Estos operadores permiten filtrar , combinar y transformar las secuencias representadas por los Observables.! • Los operadores retornan otros observables con lo cual se pueden concatenar para producir la secuencia de datos deseada.! • RxJava viene con más de 50 operadores.! • Es posible crear mas operadores para ajustarlos a nuestras necesidades.! • Los “Marble diagrams” se usan en la documentación de RxJava para explicar el funcionamiento de los operadores de una forma gráfica. !
  • 18.
    Observer de ejemplo privatestatic Observer<Integer> createIntegerObserver(){ return new Observer<Integer>() { ! public void onCompleted() { System.out.println("Sequence complete"); } ! public void onError(Throwable throwable) { String msg = throwable.getMessage(); System.out.println("Error: “+ msg); } ! public void onNext(Integer i) { System.out.println(i) } }; }
  • 19.
    Map Transforma la secuenciamediante la función Integer[] values = new Integer[]{1, 2, 3, 4, 5}; Observable<Integer> numbers = Observable.from(values); ! numbers.map(new Func1<Integer, Integer>() { public Integer call(Integer i) { return i * i; } }).subscribe(observer); Output: 1! 4! 9! 16! 25!
  • 20.
    MapMany Combina n secuenciasmediante la función Observable<String> myStockSymbols = StocksService.myPortfolio(); Observer<StockInfo> stockInfoObserver = createStockInfoObserver(); ! myStockSymbols.mapMany(new Func1<String, Observable<StockInfo>>() { public Observable<StockInfo> call(String stockSymbol) { return StocksService.getLastQuotes(stockSymbol); } ! }).subscribe(stockInfoObserver); Output: [AAPL-> 25,730120]! [GOOG -> 23,464752]! [GOOG -> 11,255009]! Sequence complete
  • 21.
    Reduce Aplica una funcióna cada item devolviendo únicamente el acumulado Integer[] values = new Integer[]{1, 2, 3, 4, 5}; Observable<Integer> numbers = Observable.from(values); Observer<Integer> observer = createIntegerObserver(); ! numbers.reduce(new Func2<Integer, Integer, Integer>() { public Integer call(Integer a , Integer b) { return a + b; } }).subscribe(observer); Output: 15! Sequence complete
  • 22.
    Filter Filtra la secuenciaen base a la función suministrada Integer[] values = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; Observable<Integer> numbers = Observable.from(values); Observer<Integer> observer = createIntegerObserver(); ! numbers.filter(new Func1<Integer, Boolean>() { public Boolean call(Integer i) { return (i % 2 == 0); } }).subscribe(observer); Output: 2! 4! 6! 8! Sequence complete
  • 23.
    SkipWhile No emite losvalores hasta que una condición se cumple Integer[] values = new Integer[]{1, 2, 3, 4, 5, 4, 3, 2, 1}; Observable<Integer> numbers = Observable.from(values); ! Observer<Integer> observer = createIntegerObserver(); numbers.skipWhile(new Func1<Integer, Boolean>() { public Boolean call(Integer i) { return (i <4); } }).subscribe(observer); Output: 4! 5! 4! 3! 2! 1! Sequence complete
  • 24.
    Take Emite solo losN elementos de la lista Integer[] values = new Integer[]{1, 2, 3, 4, 5, 4, 3, 2, 1}; Observable<Integer> numbers = Observable.from(values); ! Observer<Integer> observer = createIntegerObserver(); numbers.take(2).subscribe(observer); Output: 1! 2! Sequence complete
  • 25.
    Distinct Elimina los duplicadosde la secuencia Integer[] values = new Integer[]{1, 2, 1, 2, 3, 3, 4, 1, 2}; Observable<Integer> numbers = Observable.from(values); Observer<Integer> observer =createIntegerObserver(); ! numbers.distinct().subscribe(observer); Output: 1! 2! 3! 4! Sequence complete
  • 26.
    Merge Fusiona n secuencias Observable<Integer>odds = Observable.from(new Integer[]{1, 3, 5, 7}); Observable<Integer> evens = Observable.from(new Integer[]{2,4,6}); Observer<Integer> observer = createIntegerObserver(); Observable.merge(odds,evens).subscribe(observer); Output: 1! 3! 2! 5! 4! 7! 6! Sequence complete
  • 27.
    Zip Combina n secuenciasmediante la función ! Observable<Integer> odds = Observable.from(new Integer[]{1, 3, 5, 7}); Observable<Integer> evens = Observable.from(new Integer[]{2,4,6}); Observer<String> observer = createStringObserver(); Observable.zip(odds,evens ,new Func2<Integer, Integer, String>() { public String call(Integer a, Integer b) { return String.format("[%s,%s]",a,b); } }).subscribe(observer); Output: [1, 2]! [3, 4]! [5, 6]! Sequence complete
  • 28.
  • 29.
    Schedulers • Los observables sonmono hilo (single threaded) por defecto.! • Los scheduler se usan para introducir la concurrencia permitiendo ejecutar partes de nuestro cadena de observables concurrentemente.! • Hay dos aspectos de nuestros Observables de los que queremos poder controlar la concurrencia:! • • • En la invocación de la subscripción. Para ello usaremos el método Observable.observeOn(Scheduler s).! En las notificaciones al Observer. Para ello usaremos el método Observable.notifyOn(Scheduler s).! Hay varia implementaciones de los schedulers. Ex: CurrentThreadScheduler, ExecutorScheduler, NewThreadScheduler, …
  • 30.
    Schedulers - Ejemplo publicclass WeatherAPI ! public static Observable<WeatherData> getWeatherFromCities(String ... cities){ return Observable.from(cities).map(new Func1<String,WeatherData>() { public WeatherData call(String s) { // Call to remote api return RemoteService.getWeatherData(s); } }).subscribeOn(Schedulers.threadPoolForIO()); } }
  • 31.
    Schedulers - Ejemplo String[] cities= { "Madrid","Barcelona","Bilbao"} ; WeatherAPI.getWeatherFromCities(cities) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<WeatherData>() { // Safe to call UI code from here public void onCompleted() { … } public void onError(Throwable throwable) { … } public void onNext(String s) { }}); … }
  • 32.
    Pros • Método simple yuniforme de tratar los eventos y los errores (onNext, onError,onCompleted).! • Podemos crea APIS que mantengan el control sobre la concurrencia .! • Facilmente Testeable.! • Reusable permite que el cliente extienda/adapte la secuencia usando los operadores.!
  • 33.
    Contras • Curva de aprendizaje.! • Sintaxisde java 6 ( Java 8 lo mejora pero no esta disponible para programación en android).