rxjava, getting started - david wursteisen - 16 octobre 2014

Post on 31-May-2015

962 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Les applications sont de plus en plus interconnectées. Une architecture type WOA (Web Oriented Archiecture) et l’utilisation des micros-services nécessitent de faire de plus en plus appel à différents services web. Comment composer un résultat à partir de ces différents services, sans avoir à ce soucier de l’ordre dans lequel les serveurs vont répondre ? RxJava offre une manière élégante de faire de l’asynchrone et de la composition au sein de son application. David vous exposera les concepts de Rx (Reactive eXtension) avant de vous montrer une mise en application avec des exemples de code venant d’une application Android.

TRANSCRIPT

Getting Started

RxJava

David Wursteisen 16 Octobre 2014

David Wursteisen

@dwursteisen

Direction Expertise Innovation

David Wursteisen

Architecture distribuée

Sync/Async/Concurrence

Architecture distribuée

Architecture distribuée

Architecture distribuée

The Internet

Architecture distribuée

The Internet

Synchrone

Synchrone

Appel bloquant

Asynchrone

Asynchrone

Appel non bloquant

Complexité

Complexité

future.get();

Complexité

future1.get();future2.get();future3.get();future4.get();future5.get();future6.get();future7.get();

Complexité

future1.get();future2.get();future3.get();future4.get();future5.get();future6.get();future7.get();

Ordonnancement optimal ?

Complexité

client.execute(new Callback() { @Override public void completed(HttpResponse response) { }});

Complexité

client.execute(new Callback() { @Override public void completed(HttpResponse response) { client.execute(new Callback() { @Override public void completed(HttpResponse response) { } });

}});

Complexité

client.execute(new Callback() { @Override public void completed(HttpResponse response) { client.execute(new Callback() { @Override public void completed(HttpResponse response) { client.execute(new Callback() { @Override public void completed(HttpResponse response) { } }); }});

}});

Complexité

client.execute(new Callback() { @Override public void completed(HttpResponse response) { client.execute(new Callback() { @Override public void completed(HttpResponse response) { client.execute(new Callback() { @Override public void completed(HttpResponse response) { } }); }});

}});

Callback hell

Concurrence

Concurrence

Concurrence

Concurrence

Concurrence

Concurrence

RxJava permet de manipuler des évènements d’une manière synchrone et/ou asynchrone.

Historique

Il était une fois...

Historique

Historique

Historique

Historique

Historique

ReactiveX.io

Observables

Travailler avec des flux

Flux d’évènements fini

Évènements Fin du flux

Flux d’évènements en erreur

Évènements Erreur

Flux d’évènements infini

Évènements

Flux d’évènements

Observable.never()

Observable.empty()

Observable.just(1)

Observable.from(1, 2, 3)

Observable.range(1, 4400)

Observable.timer(5, TimeUnit.SECONDS)

Observable.create(...)

Flux d’évènements

Observable.never()

Observable.empty()

Observable.just(1)

Observable.from(1, 2, 3)

Observable.range(1, 4400)

Observable.timer(5, TimeUnit.SECONDS)

Observable.create(...)

Flux d’évènements

Observable.never()

Observable.empty()

Observable.just(1)

Observable.from(1, 2, 3)

Observable.range(1, 4400)

Observable.timer(5, TimeUnit.SECONDS)

Observable.create(...)

1

Flux d’évènements

Observable.never()

Observable.empty()

Observable.just(1)

Observable.from(1, 2, 3)

Observable.range(1, 4400)

Observable.timer(5, TimeUnit.SECONDS)

Observable.create(...)

1 2 3

Flux d’évènements

Observable.never()

Observable.empty()

Observable.just(1)

Observable.from(1, 2, 3)

Observable.range(1, 4400)

Observable.timer(5, TimeUnit.SECONDS)

Observable.create(...)

1 4400

Flux d’évènements

Observable.never()

Observable.empty()

Observable.just(1)

Observable.from(1, 2, 3)

Observable.range(1, 4400)

Observable.timer(5, TimeUnit.SECONDS)

Observable.create(...)

0

t

t + 5 secondes

Flux d’évènements

Observable.never()

Observable.empty()

Observable.just(1)

Observable.from(1, 2, 3)

Observable.range(1, 4400)

Observable.timer(5, TimeUnit.SECONDS)

Observable.create(...)

A C

Flux d’évènements

λ ϕ φ

json json jsonObservable<json>

Observable<Integer>

Observable<Click>

Observer

Push des données

Observer

OnNext* (OnCompleted|OnError)?

Observer

OnNext* (OnCompleted|OnError)?

Observer

OnNext* (OnCompleted|OnError)?

Observer

OnNext* (OnCompleted|OnError)?

Observer

Observable.range(1, 4400)

Observer

Observable.range(1, 4400).subscribe()

Observer

Observable.range(1, 4400).subscribe(onNext)

Observer

Observable.range(1, 4400).subscribe(System.out::println)

Observer

Observable.range(1, 4400).subscribe(System.out::println, onError)

Observer

Observable.range(1, 4400).subscribe(System.out::println, System.err::println)

Observer

Observable.range(1, 4400).subscribe(System.out::println, System.err::println,onCompleted)

Observer

Observable.range(1, 4400).subscribe(System.out::println, System.err::println,

() -> System.out.println(“finished”))

Manipulation d’évènements

Quand l’écoute ne suffit plus

Manipulation d’évènements

0 1

Manipulation d’évènements

0 1

map

Manipulation d’évènements

0 1

A B

map

Manipulation d’évènements

1 4

Manipulation d’évènements

1 4

filter ( x <= 2 )

Manipulation d’évènements

1 4

1

filter ( x <= 2 )

Manipulation d’évènements

1 2

Manipulation d’évènements

1 2

delay ( 5, SECONDS )

Manipulation d’évènements

1 2

1

delay ( 5, SECONDS )

2

Manipulation d’évènements

Observable.from(0, 1, 2, 3, 4)

Observable<Integer>

Manipulation d’évènements

Observable.from(0, 1, 2, 3, 4) .filter((i) -> i < 3)

Observable<Integer>Observable<Integer>

Manipulation d’évènements

Observable.from(0, 1, 2, 3, 4) .filter((i) -> i < 3) .delay(5, TimeUnit.SECONDS)

Observable<Integer>Observable<Integer>Observable<Integer>

Manipulation d’évènements

Observable.from(0, 1, 2, 3, 4) .filter((i) -> i < 3) .delay(5, TimeUnit.SECONDS) .map((i) -> Character.toString((char)(i + 'A')))

Observable<Integer>Observable<Integer>Observable<Integer>

Observable<String>

Manipulation d’évènements

Observable.from(0, 1, 2, 3, 4) .filter((i) -> i < 3) .delay(5, TimeUnit.SECONDS) .map((i) -> Character.toString((char)(i + 'A'))) .subscribe(System.out::println);

Observable<Integer>Observable<Integer>Observable<Integer>

Observable<String>

Manipulation d’évènements

Observable.from(0, 1, 2, 3, 4) .filter((i) -> i < 3) .delay(5, TimeUnit.SECONDS) .map((i) -> Character.toString((char)(i + 'A'))) .subscribe(System.out::println);

0, 1, 2, 3, 4 => A, B, C

Observable<Integer>Observable<Integer>Observable<Integer>

Observable<String>

Manipulation d’évènements

Manipulation d’évènements

Manipulation d’évènements

Composition

Création d’un flux à partir d’un ensemble de flux

Composition

Composition

Composition

Mise en pratique de composition

Learn from the trenches

Composition

Composition

Composition

Composition

Composition

Composition

merge

Composition

merge

Composition

Composition

Composition

zip

Composition

zip

Subscription

Et gestion de l’unsubscribe

Subscription

Observable.create(new OnSubscribe<T>() { … });

Subscription

Observable.create(new OnSubscribe<T>() {

@Override public void call(Subscriber<? super T> s) { s.onNext(123); s.onCompleted(); }

});

Subscription

Observable.create(new OnSubscribe<T>() {

@Override public void call(Subscriber<? super T> s) { s.onNext(123); s.onCompleted(); }

});

Émission synchronne

Subscription

Observable.create(new OnSubscribe<T>() { @Override public void call(Subscriber<? super T> subscriber) { // ... httpClient.execute(httpRequest, new FutureCallback<HttpResponse>() { @Override public void completed(String content) { subscriber.onNext(content); subscriber.onCompleted(); }

@Override public void failed(Exception e) { subscriber.onError(e); } }); }});

Subscription

Observable.create(new OnSubscribe<T>() { @Override public void call(Subscriber<? super T> subscriber) { // ... httpClient.execute(httpRequest, new FutureCallback<HttpResponse>() { @Override public void completed(String content) { subscriber.onNext(content); subscriber.onCompleted(); }

@Override public void failed(Exception e) { subscriber.onError(e); } }); }});

Subscription

Observable.create(new OnSubscribe<T>() { @Override public void call(Subscriber<? super T> subscriber) { // ... httpClient.execute(httpRequest, new FutureCallback<HttpResponse>() { @Override public void completed(String content) { subscriber.onNext(content); subscriber.onCompleted(); }

@Override public void failed(Exception e) { subscriber.onError(e); } }); }});

Subscription

Observable.create(new OnSubscribe<T>() { @Override public void call(Subscriber<? super T> subscriber) { // ... httpClient.execute(httpRequest, new FutureCallback<HttpResponse>() { @Override public void completed(String content) { subscriber.onNext(content); subscriber.onCompleted(); }

@Override public void failed(Exception e) { subscriber.onError(e); } }); }});

Émission asynchronne

Subscription

Observable.create(new OnSubscribe<T>() { @Override public void call(Subscriber<? super T> subscriber) { // ... httpClient.execute(httpRequest, new FutureCallback<HttpResponse>() { @Override public void completed(String content) { subscriber.onNext(content); subscriber.onCompleted(); }

@Override public void failed(Exception e) { subscriber.onError(e); } }); }});

Propagation des erreurs

Subscription

La souscription permet d’uniformiser des API différentes par leurs natures (Callback, etc...)

Unsubscribe

Subscription subscription = Observable.interval(1, TimeUnit.SECONDS).subscribe();

Unsubscribe

Subscription subscription = Observable.interval(1, TimeUnit.SECONDS).subscribe();

Souscription

Unsubscribe

Subscription subscription = Observable.interval(1, TimeUnit.SECONDS).subscribe();

Handler sur la souscription

Unsubscribe

Subscription subscription = Observable.interval(1, TimeUnit.SECONDS).subscribe();/* ... */subscription.unsubscribe();

Unsubscribe

Subscription subscription = Observable.interval(1, TimeUnit.SECONDS).subscribe();/* ... */subscription.unsubscribe();

Arrêt de la souscription

Schedulers

Schedulers

observableReadingSynchronously(“strings.txt”)

.take(10) .delay(1, SECONDS) .map(parse())

.map(n -> “=> ” + n)) .subscribe(to_the_view())

Schedulers

main

Schedulers

observableReadingSynchronously(“strings.txt”)

.take(10) .delay(1, SECONDS) .map(parse())

.map(n -> “=> ” + n)) .subscribe(to_the_view())

Schedulers

Computation

IO

UI

main

Schedulers

Computation

IO

UI

main

Schedulers

Computation

IO

UI

main

Schedulers

Computation

IO

UI

main

Schedulers

Computation

IO

UI

main

Schedulers

Computation

IO

UI

main

Schedulers

observableReadingSynchronously(“strings.txt”) .subscribeOn(scheduler) .take(10) .delay(1, SECONDS, scheduler) .map(parse()) .observeOn(scheduler) .map(n -> “=> ” + n)) .subscribe(to_the_view())

Schedulers

observableReadingSynchronously(“strings.txt”) .subscribeOn(Schedulers.io()) .take(10) .delay(1, SECONDS, Schedulers.computation()) .map(parse()) .observeOn(Schedulers.from(uiExecutor())) .map(n -> “=> ” + n)) .subscribe(to_the_view())

Schedulers

UI

Computation

Schedulers

UI

Computation

Schedulers

UI

Computation

Schedulers

UI

Computation

Schedulers

UI

Computation

Hot & Cold Observable

Cold Observable

Observable<Integer> obs = Observable.from(1, 2, 3, 4);

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

Cold Observable

Observable<Integer> obs = Observable.from(1, 2, 3, 4);

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

Cold Observable

Observable<Integer> obs = Observable.from(1, 2, 3, 4);

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

Subscribe

Cold Observable

Observable<Integer> obs = Observable.from(1, 2, 3, 4);

obs.subscribe(System.out::println);

obs.subscribe(System.out::println); Subscribe

Cold Observable

Observable<Integer> obs = Observable.from(1, 2, 3, 4);

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);Souscription différente

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();Subscribe

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();

Partage la même souscription

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

obs.connect();

Hot Observable

ConnectableObservable<Integer> obs = Observable.from(1, 2, 3, 4).publish();

obs.connect();

obs.subscribe(System.out::println);

obs.subscribe(System.out::println);

Souscription

Cold & Hot Observable

Cold Observable = flux passif

Hot Observable = flux actif

Back Pressure

Contrôler la production

Back Pressure

Production

Back Pressure

Production

buffer

Back Pressure

Production

Pression arrière

Back Pressure

Production

Pression arrière

Demande de production de n élements

Retour d’expérience

Opérateurs

Observable.from(1, 2, 3, 4) .reduce(new LinkedList<Integer>(), (seed, value) -> { seed.add(value); return seed; }) .first() .subscribe(System.out::println);

Opérateurs

Observable.from(1, 2, 3, 4) .reduce(new LinkedList<Integer>(), (seed, value) -> { seed.add(value); return seed; }) .first() .subscribe(System.out::println);

Opérateurs

Observable.from(1, 2, 3, 4) .toList() .first() .subscribe(System.out::println);

Opérateurs

Observable.from(1, 2, 3, 4) .toList() .first() .subscribe(System.out::println);

Opérateurs

Observable.from(1, 2, 3, 4) .toList() .first() .subscribe(System.out::println);

Différence entre first() / single() / take(1) ?

Gestion des erreurs

Observable.from(1, 2, 3, 4) .toList() .single() .subscribe(System.out::println);

Gestion des erreurs

Observable.from(1, 2, 3, 4) .toList() .single() .subscribe(System.out::println);

Notification des erreurs absentes

Gestion des erreurs

static { RxJavaPlugins.getInstance().registerErrorHandler(new RxJavaErrorHandler() { @Override public void handleError(Throwable e) { e.printStackTrace(); } });}

Lambda & Java 8

Observable.from(1, 2, 3, 4) .filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer i) { return i > 3; } }) .subscribe(new Action1<Integer>() { @Override public void call(Integer x) { System.out.println(x); } });

Lambda & Java 8

Observable.from(1, 2, 3, 4) .filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer i) { return i > 3; } }) .subscribe(new Action1<Integer>() { @Override public void call(Integer x) { System.out.println(x); } });

Bruit

Lambda & Java 8

Observable.from(1, 2, 3, 4) .filter(i -> i > 3) .subscribe(System.out::println);

Lambda & Java 8

Observable.from(1, 2, 3, 4) .filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer i) { return i > 3; } }) .subscribe(new Action1<Integer>() { @Override public void call(Integer x) { System.out.println(x); } });

Observable.from(1, 2, 3, 4) .filter(i -> i > 3) .subscribe(System.out::println);

Retrolambda

Concurrence

obs1.mergeWith(obs2) .take(5) .subscribe(System.out::println);

Concurrence

obs1.mergeWith(obs2) .take(5) .subscribe(System.out::println);

Concurrence

obs1.mergeWith(obs2) .take(5) .subscribe(System.out::println);

Doit gérer la concurrence

Concurrence

obs1.mergeWith(obs2) .take(5) .subscribe(System.out::println);

Concurrence

obs1.mergeWith(obs2) .take(5) .subscribe(System.out::println);

non concurrence

Sync & Async

Observable<Integer> generator();

Sync & Async

Observable<Integer> generator();

Sync ?

Sync & Async

Observable<Integer> generator();

Sync ? Async ?

Sync & Async

Observable<Integer> generator();

Sync ? Async ?

Computation ?

Sync & Async

Observable<Integer> generator();

Sync ? Async ?

Computation ? Acteur ?

“Leak” des Observables

everything is an event

“Leak” des Observables

ViewPager

“Leak” des Observables

ViewPager

Preferences

Observable

“Leak” des Observables

ViewPager

Preferences

UserService

Observable

Observable

Future<RxJava>

Future<RxJava>

Support RxJava

Reactive Streams

Reactive Streams

Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure on the JVM.

http://www.reactive-streams.org/

Reactive Streams

RxJava | Akka Streams | Reactor Composable | Ratpack

Reactive Streams

RxJava | Akka Streams | Reactor Composable | Ratpack

> 700 Ko | Java | Android

Reactive Streams

RxJava | Akka Streams | Reactor Composable | Ratpack

> 2.5 Mo | Scala | Akka

Reactive Streams

RxJava | Akka Streams | Reactor Composable | Ratpack

~1Mo | Java | RingBufferDispatcher

Reactive Streams

RxJava | Akka Streams | Reactor Composable | Ratpack

Java 8 | Http

Si il ne fallait retenir qu’une chose

Si il ne fallait retenir qu’une chose

RxJava est un modèle de programmation pour écrire des applications asynchrones

Frontend | Backend | Crossplatform

Questions ?

david.wursteisen@soat.fr@dwursteisen

top related