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.!
!
ObserverObserver<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("[email protected]"); observer.onNext("[email protected]"); observer.onNext("[email protected]"); observer.onNext("[email protected]");! 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. !
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) } };}
Observer de ejemplo
Map
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!
Transforma la secuencia mediante la función
MapMany
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);
[AAPL -> 25,730120]![GOOG -> 23,464752]![GOOG -> 11,255009]!Sequence complete
Output:
Combina n secuencias mediante la función
Reduce
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);
15!Sequence complete
Output:
Aplica una función a cada item devolviendo únicamente el acumulado
Filter
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);
2!4!6!8!Sequence complete
Output:
Filtra la secuencia en base a la función suministrada
SkipWhile
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);
4!5!4!3!2!1!Sequence complete
Output:
No emite los valores hasta que una condición se cumple
Take
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);
1!2!Sequence complete
Output:
Emite solo los N elementos de la lista
Distinct
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);
1!2!3!4!Sequence complete
Output:
Elimina los duplicados de la secuencia
Merge
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);
1!3!2!5!4!7!6!Sequence complete
Output:
Fusiona n secuencias
Zip
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);
[1, 2]![3, 4]![5, 6]!Sequence complete
Output:
Combina n secuencias mediante la función
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 - Ejemplopublic 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 - EjemploString [] 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).