Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJava est mort, vive RxJava 2 !

David
April 10, 2017

RxJava est mort, vive RxJava 2 !

La migration de RxJava 2 à commencé en 2016. Mais 2017 sera sont année phare et va pouvoir profiter du chemin déjà tracé par sa précédente version.

Quels sont les changements apportés par cette nouvelle version, en terme d’API ou de performances ? En quoi RxJava et RxJava 2 sont-ils différents ? Faut-il migrer sur RxJava 2 tout de suite ?

Cette conférence fera un bref historique des ces bibliothèques avant de répondre à ces différentes questions.

(Android Makers - 10 Avril Paris 2017)

David

April 10, 2017
Tweet

More Decks by David

Other Decks in Programming

Transcript

  1. Future ExecutorService ex = Executors.newCachedThreadPool();
 Future<String> future = ex.submit(() ->

    longProcessing());
 String result = future.get(); Appel bloquant
  2. Future Future<?> future1 = /* ... */
 Future<?> future2 =

    /* ... */
 Future<?> future3 = /* ... */
 Future<?> future4 = /* ... */
 Future<?> future5 = /* ... */ Orchestration optimale ?
  3. Callback RemoteService service = buildRemoteService();
 service.getUser(id -> {
 service.getData(id, data

    -> {
 service.getSomething(data, whut -> { service.neverEndingCallBack(whut, () -> { }); });
 });
 }); Callback Hell
  4. API pour manipuler 
 des événements de manière synchrone ou

    asynchrone à travers un flux d’événements
  5. RxView.clicks(btn)
 .doOnNext(evt -> rotation.playFromStart())
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData())
 .observeOn(AndroidSchedulers.mainThread())
 .doOnNext(evt

    -> {
 rotation.stop();
 btn.setRotate(0);
 })
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe(); Écoute des clicks Démarrage animation Appel web service Arrêt de l’animation Mise à jour de l’UI Abonnement
  6. Création des 
 Reactive Extensions Création de RxJava Participation active

    Reprise de 
 RxJava & RxJava 2 Création de Reactor Participation à Reactor
  7. RxJava n’est pas compatible 
 avec Reactive Streams (il faut

    alors utiliser un adapteur : RxJavaReactiveStreams) https://github.com/ReactiveX/RxJavaReactiveStreams
  8. onNext * ( onError | onComplete ) 
 onNext *

    ( onError | onCompleted ) RxJava Reactive Streams
  9. onNext * ( onError | onComplete ) 
 onNext *

    ( onError | onCompleted ) RxJava Reactive Streams Nom différent
  10. RxJava Contrat Backpressure Observable [N] Oui Single [1] Non Completable

    [0] Non Ajouté après coup Appel Web service Processus d’arrière plan
  11. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  12. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  13. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  14. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  15. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Écoute de la websocket Observable
  16. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Composition d’une réponse à partir de 3 webservices Single
  17. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Completable Exécuter 2 jobs
  18. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Écoute de la websocket Observable Composition d’une réponse à partir de 3 webservices Single Completable Exécuter 2 jobs
  19. RxJava 2 Contrat Backpressure Observable [N] Non Single [1] Non

    Completable [0] Non Maybe [0|1] Non Nouveau ! Concept « similaire » à Optional
  20. acceptedIntent
 .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false))
 .concatMap(intent -> approximatedEngine.detectCurrentPlace())
 .doOnNext(score ->

    Log.info(TAG, "Scan completed with result " + score))
 .concatMap(this::detectSleepMode)
 .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))
 .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))
 .subscribe()
  21. acceptedIntent
 .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false)) .onBackpressureDrop()
 .concatMap(intent -> approximatedEngine.detectCurrentPlace())
 .doOnNext(score

    -> Log.info(TAG, "Scan completed with result " + score))
 .onBackpressureDrop() .concatMap(this::detectSleepMode)
 .onBackpressureDrop()
 .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))
 .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))
 .subscribe() Ajouté dans un moment de panique
  22. RxJava 2 Contrat Backpressure Observable [N] Non Single [1] Non

    Completable [0] Non Maybe [0|1] Non Nouveau ! Concept « similaire » à Optional
  23. RxJava 2 Contrat Backpressure Observable [N] Non Single [1] Non

    Completable [0] Non Maybe [0|1] Non Flowable [N] Oui Nouveau ! Observable avec 
 back pressure Concept « similaire » à Optional
  24. Observable → moins de 1000 éléments → Gestion d’élément d’interface

    graphique → Remplacement de Stream Java Flowable → plus de 10 000 éléments → contrôle de l’émission de données → Flux réseau avec contrôle de débit
  25. P o u v o i r u t i

    l i s e r u n e biblio t hèq ue utilisant Reactive Streams dans son projet RxJava 2 (et vice versa)
  26. all amb ambArray ambWith any as awaitOnSubscribe blockFirst blockFirstMillis blockLast

    blockLastMillis blockingFirst blockingForEach blockingIterable blockingLast blockingLatest blockingMostRecent blockingNext blockingSingle blockingSubscribe buffer bufferMillis bufferSize bufferTimeout bufferTimeoutMillis bufferUntil bufferWhile cache cacheWithInitialCapacity cancelOn cast checkpoint collect collectInto collectList collectMap collectMultimap collectSortedList combineLatest combineLatestDelayError compose concat concatArray concatArrayDelayError concatArrayEager concatDelayError concatEager concatMap concatMapDelayError concatMapEager concatMapEagerDelayError concatMapIterable concatWith contains count create debounce defaultIfEmpty defer delay delayElements delayElementsMillis delayMillis delaySubscription delaySubscriptionMillis dematerialize distinct distinctUntilChanged doAfterNext doAfterTerminate doFinally doOnCancel doOnComplete doOnEach doOnError doOnLifecycle doOnNext doOnRequest doOnSubscribe doOnTerminate elapsed elementAt elementAtOrError empty equals error filter first firstElement firstEmitting firstEmittingWith firstOrError flatMap flatMapCompletable flatMapIterable flatMapMaybe flatMapSequential flatMapSingle forEach forEachWhile from fromArray fromCallable fromFuture fromIterable fromPublisher fromStream generate getClass getPrefetch groupBy groupJoin handle hasElement hasElements hashCode hide ignoreElements interval intervalMillis intervalRange isEmpty join just last lastElement lastOrError lift limitRate log map mapError materialize merge mergeArray mergeArrayDelayError mergeDelayError mergeSequential mergeWith never next notify notifyAll observeOn ofType onBackpressureBuffer onBackpressureDrop onBackpressureError onBackpressureLatest onErrorResumeNext onErrorResumeWith onErrorReturn onErrorReturnItem onExceptionResumeNext onTerminateDetach parallel publish publishNext publishOn range rangeLong rebatchRequests reduce reduceWith repeat repeatUntil repeatWhen replay replayMillis retry retryUntil retryWhen safeSubscribe sample sampleFirst sampleFirstMillis sampleMillis sampleTimeout scan scanWith sequenceEqual serialize share single singleElement singleOrEmpty singleOrError skip skipLast skipMillis skipUntil skipUntilOther skipWhile sort sorted startWith startWithArray strict subscribe subscribeOn subscribeWith switchIfEmpty switchMap switchMapDelayError switchOnError switchOnNext switchOnNextDelayError take takeLast takeMillis takeUntil takeUntilOther takeWhile test then thenEmpty thenMany throttleFirst throttleLast throttleWithTimeout timeInterval timeout timeoutMillis timer timestamp to toFuture toIterable toList toMap toMultimap toObservable toSortedList toStream toString transform unsafeCreate unsubscribeOn using wait window windowMillis windowTimeout windowTimeoutMillis windowUntil windowWhile withLatestFrom zip zipArray zipIterable zipWith zipWithIterable
  27. RxJava RxJava 2 flatMap flatMap Émission d’aucune, une ou plusieurs

    valeurs amb amb Émission des valeurs du flux répondant en premier … … … debounce debounce Ignore les événements pendant un laps de temps
  28. RxJava RxJava 2 Observable.fromAsync Observable.create Observable<T> first() Maybe<T> firstElement() Observable<T>

    firstOrDefault(T) Single<T> first(T) Observable<T> ignoreElements() Completable ignoreElements()
  29. RxJava RxJava 2 Observable.fromAsync Observable.create Observable<T> first() Maybe<T> firstElement() Observable<T>

    firstOrDefault(T) Single<T> first(T) Observable<T> ignoreElements() Completable ignoreElements()
  30. RxJava RxJava 2 Observable.fromAsync Observable.create Observable<T> first() Maybe<T> firstElement() Observable<T>

    firstOrDefault(T) Single<T> first(T) Observable<T> ignoreElements() Completable ignoreElements()
  31. RxJava RxJava 2 Observable.fromAsync Observable.create Observable<T> first() Maybe<T> firstElement() Observable<T>

    firstOrDefault(T) Single<T> first(T) Observable<T> ignoreElements() Completable ignoreElements()
  32. RxJava RxJava 2 Observable.fromAsync Observable.create Observable<T> first() Maybe<T> firstElement() Observable<T>

    firstOrDefault(T) Single<T> first(T) Observable<T> ignoreElements() Completable ignoreElements()
  33. https://github.com/ReactiveX/RxJava/wiki/Implementing-custom-operators-(draft) writing operators is hard when one writes an operator,

    the Observable protocol, unsubscription, backpressure and concurrency have to be taken into account and adhered to the letter
  34. RxView.clicks(btn) 
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData())
 .observeOn(Schedulers.computation())
 .flatMap(data -> intensiveComputation(data))


    .observeOn(AndroidSchedulers.mainThread())
 .doOnNext(value -> btn.setText("Data: " + value)) 
 .subscribe(); entrée/sortie calculs Thread graphique
  35. RxJava RxJava 2 Description io() io() Pool de Thread qui

    grossit au besoin computation() computation() Pool fini de Thread single() single() Pool de 1 Thread immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  36. RxJava RxJava 2 Description io() io() Pool de Thread qui

    grossit au besoin computation() computation() Pool fini de Thread single() single() Pool de 1 Thread immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  37. RxJava RxJava 2 Description io() io() Pool de Thread qui

    grossit au besoin computation() computation() Pool fini de Thread single() single() Pool de 1 Thread immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  38. RxJava RxJava 2 Description io() io() Pool de Thread qui

    grossit au besoin computation() computation() Pool fini de Thread single() single() Pool de 1 Thread immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  39. RxJava RxJava 2 Description io() io() Pool de Thread qui

    grossit au besoin computation() computation() Pool fini de Thread single() single() Pool de 1 Thread immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer Absent pour votre bien
  40. RxJava RxJava 2 Description io() io() Pool de Thread qui

    grossit au besoin computation() computation() Pool fini de Thread single() single() Pool de 1 Thread immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  41. Flowable.range(1, 100000)
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 


    @Override
 public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 });
  42. Flowable.range(1, 100000)
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 


    @Override
 public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 }); Garder la référence de l’abonnement Demander l’émission des éléments suivants Demande l’émission des premiers éléments
  43. Flowable.range(1, 100000)
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 


    @Override
 public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 }); Reactive Streams
  44. Flowable.range(1, 100000)
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 


    @Override
 public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 }); Contrôle de l’émission
  45. source()
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 
 @Override


    public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 }); Update GPS Liste déroulante
  46. -Jake Wharton « Unless you can model your entire system

    synchronously, a single asynchronous source breaks imperative programming »
  47. -Jake Wharton « Unless you can model your entire system

    synchronously, a single asynchronous source breaks imperative programming »
  48. RxJava
 RxJava 2 Flowable.just Émission d’une valeur existante Flowable.defer Émission

    tardive d’un Observable Flowable.fromCallable Émission à partir d’un appel de fonction Flowable.create Contrôle manuel de l’émission des événements Flowable.using Gestion d’une ressource Flowable.fromPublisher Utilisation d’un Publisher (Reactive Streams) Flowable.generate Utilisation d’un générateur de valeurs
  49. RxJava
 RxJava 2 Flowable.just Émission d’une valeur existante Flowable.defer Émission

    tardive d’un Observable Flowable.fromCallable Émission à partir d’un appel de fonction Flowable.create Contrôle manuel de l’émission des événements Flowable.using Gestion d’une ressource Flowable.fromPublisher Utilisation d’un Publisher (Reactive Streams) Flowable.generate Utilisation d’un générateur de valeurs
  50. RxJava
 RxJava 2 Flowable.just Émission d’une valeur existante Flowable.defer Émission

    tardive d’un Observable Flowable.fromCallable Émission à partir d’un appel de fonction Flowable.create Contrôle manuel de l’émission des événements Flowable.using Gestion d’une ressource Flowable.fromPublisher Utilisation d’un Publisher (Reactive Streams) Flowable.generate Utilisation d’un générateur de valeurs
  51. RxJava
 RxJava 2 Flowable.just Émission d’une valeur existante Flowable.defer Émission

    tardive d’un Observable Flowable.fromCallable Émission à partir d’un appel de fonction Flowable.create Contrôle manuel de l’émission des événements Flowable.using Gestion d’une ressource Flowable.fromPublisher Utilisation d’un Publisher (Reactive Streams) Flowable.generate Utilisation d’un générateur de valeurs
  52. RxJava
 RxJava 2 Flowable.just Émission d’une valeur existante Flowable.defer Émission

    tardive d’un Observable Flowable.fromCallable Émission à partir d’un appel de fonction Flowable.create Contrôle manuel de l’émission des événements Flowable.using Gestion d’une ressource Flowable.fromPublisher Utilisation d’un Publisher (Reactive Streams) Flowable.generate Utilisation d’un générateur de valeurs
  53. Observable.<Event>create(emitter -> {
 Callback listener = new Callback() {
 @Override


    public void onEvent(Event e) {
 emitter.onNext(e);
 if (e.isLast()) {
 emitter.onComplete();
 }
 }
 
 @Override
 public void onFailure(Exception e) {
 emitter.onError(e);
 }
 };
 
 AutoCloseable c = api.someMethod(listener);
 
 emitter.setCancellation(c::close);
 
 }); Contract RxJava Contract RxJava Désabonnement
  54. Flowable.<Event>create(emitter -> {
 Callback listener = new Callback() {
 @Override


    public void onEvent(Event e) {
 emitter.onNext(e);
 if (e.isLast()) {
 emitter.onComplete();
 }
 }
 
 @Override
 public void onFailure(Exception e) {
 emitter.onError(e);
 }
 };
 
 AutoCloseable c = api.someMethod(listener);
 
 emitter.setCancellation(c::close);
 
 }, BackpressureStrategy.BUFFER); Backpressure
  55. RxJava 2 Observable.just(null);
 
 Single.just(null);
 
 Observable.fromCallable(() -> null)
 .subscribe(System.out::println,

    Throwable::printStackTrace);
 
 Observable.just(1).map(v -> null)
 .subscribe(System.out::println, Throwable::printStackTrace); NullPointerException NullPointerException NullPointerException N ullPointerException
  56. Observable.range(1, 10)
 .map(i -> {
 if (i % 2 ==

    0) {
 return null;
 } else {
 return i;
 }
 })
 .filter(i -> i != null)
 .subscribe(System.out::println); émission de null filtre de null RxJava
  57. Observable.range(1, 10)
 .flatMap(i -> {
 if (i % 2 ==

    0) {
 return Observable.empty();
 } else {
 return Observable.just(i);
 }
 })
 .subscribe(System.out::println); émission de empty RxJava 2
  58. Disposable abonnement = observeClicks()
 .map(evt -> "click !")
 .subscribe();
 


    CompositeDisposable abonnements = new CompositeDisposable(abonnement);
 
 abonnements.clear(); Subscription → Disposable CompositeSubscription → CompositeDisposable
  59. rx.Action1 rx.Func1 RxJava RxJava 2 rx.Func2 rx.Func3 rx.Action2 io.reactivex.functions.Consumer io.reactivex.functions.Function

    io.reactivex.functions.BiFunction io.reactivex.functions.Function3 io.reactivex.functions.BiConsumer Suivre les conventions Java 8
  60. RxJavaInterop.toV2Observable(rx.Observable.just(1, 2, 3))
 .firstElement()
 .subscribe();
 
 RxJavaInterop.toV1Observable(io.reactivex.Observable.just(1, 2, 3), 


    BackpressureStrategy.DROP)
 .first()
 .subscribe(); https://github.com/akarnokd/RxJava2Interop RxJava → RxJava 2 RxJava 2 → RxJava
  61. public class AndroidApp extends Application {
 
 
 static {


    
 RxJavaPlugins.getInstance().registerErrorHandler(new RxJavaErrorHandler() {
 @Override
 public void handleError(Throwable e) {
 e.printStackTrace();
 Log.error("RX-EXCEPTION", "An Stream throw an exception ", e);
 }
 });
 } } Doit être défini en 1er Gestion d’erreur par défaut
  62. rx.exceptions.OnErrorNotImplementedException: Sequence contains too many elements at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java: 386) at

    rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java: 383) at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44) at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153) at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115) at rx.internal.operators.OperatorSingle$ParentSubscriber.onNext(OperatorSingle.java:97) at rx.internal.operators.OnSubscribeRange$RangeProducer.slowPath(OnSubscribeRange.java:90) at rx.internal.operators.OnSubscribeRange$RangeProducer.request(OnSubscribeRange.java:68) at rx.Subscriber.setProducer(Subscriber.java:211) at rx.internal.operators.OnSubscribeRange.call(OnSubscribeRange.java:38) Stacktrace inexploitable
  63. RxJavaHooks.enableAssemblyTracking(); […] Caused by: rx.exceptions.AssemblyStackTraceException: Assembly trace: at rx.Observable.create(Observable.java:100) at

    rx.Observable.lift(Observable.java:237) at rx.Observable.single(Observable.java:9330) at rxjava2.BasicExampleTest.stacktrace(BasicExampleTest.java:225) rx.Observable.range(1, 100)
 .single()
 .subscribe();
  64. enableTracing n’est pas encore supporté par RxJava 2 (pour cela,

    il faut utiliser RxJava2Extensions) https://github.com/akarnokd/RxJava2Extensions
  65. for (int x = 0; x < 10_000; x++) {


    
 Observable.interval(10, TimeUnit.MILLISECONDS)
 .takeWhile(i -> take.get())
 .flatMap(i -> Observable.range(1, 100))
 .subscribe();
 }
  66. Merci pour votre attention On reste en contact ? [email protected]

    @dwursteisen http://blog.soat.fr RefCard RxJava 2 bientôt disponible !