Programación Reactiva en Android

Post on 13-Jun-2015

1.787 views 6 download

description

Ponencia ofrecida por Oier Blasco en DroidconMAD2013. Sinopsis: La programación reactiva es un paradigma de programación que se centra en los flujos de datos. La presentación trata de cómo podemos usar la programación reactiva para simplificar la programación de tareas asíncronas en android (principalmente las aplicaciones que consumen datos de servicios remotos). Para ello comenzaremos la presentación con una introducción sobre los motivos y los fundamentos de la programación reactiva y como los implementa RxJava (El port open-source hecho por Netflix de la Rx extensions de microsoft). El la segunda para parte de la presentación veremos algunos ejemplos concreto de cómo podemos aplicar estos principios a problemas cotidianos en android.

Transcript of Programación Reactiva en Android

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("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. !

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).