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.
4. Intent Service
•
No especifica como notificar a los clientes.!
•
Ningún controlo sobre la concurrencia.!
•
No especifican método de gestión de errores.
5. 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.
11. 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.
12. Observable
•
Una secuencia de valores , finita o infinita.!
•
Permite la subscripción de observer mediante el método
subscribe.!
•
Lazy evaluation.!
13. 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.!
!
14. 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!!!!!”);
}
}
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();
}
!
});
17. 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. !
18. 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)
}
};
}
19. 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!
21. 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
22. 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
23. 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
24. 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
25. 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
29. 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, …
30. 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());
}
}
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 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.!