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. RxJava est mort,
    Vive RxJava 2 !

    View Slide

  2. David
    Wursteisen

    View Slide

  3. View Slide

  4. Don’t panic !

    View Slide

  5. View Slide

  6. Écrire du code asynchrone : 

    ça craint

    View Slide

  7. Future
    ExecutorService ex = Executors.newCachedThreadPool();

    Future future = ex.submit(() -> longProcessing());

    String result = future.get();
    Appel bloquant

    View Slide

  8. Future
    Future> future1 = /* ... */

    Future> future2 = /* ... */

    Future> future3 = /* ... */

    Future> future4 = /* ... */

    Future> future5 = /* ... */
    Orchestration
    optimale ?

    View Slide

  9. Callback
    RemoteService service = buildRemoteService();

    service.getUser(id -> {

    service.getData(id, data -> {

    service.getSomething(data, whut -> {
    service.neverEndingCallBack(whut, () -> {
    });
    });

    });

    });
    Callback Hell

    View Slide

  10. Relationship Status:

    it’s complicated

    View Slide

  11. Le problème
    du code synchrone

    View Slide

  12. Synchrone
    Attente de la réponse
    Appelant
    Appelé

    View Slide

  13. Impacte le temps
    de réponse
    Serveur lent

    View Slide

  14. Il y a toujours
    un truc qui ne
    marche pas
    ça m’énerve !

    View Slide

  15. View Slide

  16. Ça ne
    marche pas !
    ça a planté ?
    dans le
    doute, reboot

    View Slide

  17. Asynchrone
    Appelant
    Appelé
    Traitement continu

    View Slide

  18. L’asynchrone permet de profiter
    du temps d’attente

    View Slide

  19. L’asynchrone permet de casser
    le couplage
    temporel

    View Slide

  20. Impact minimum
    sur le temps de
    réponse

    View Slide

  21. View Slide

  22. Écrire du code asynchrone
    facilement ?

    View Slide

  23. View Slide

  24. API pour manipuler 

    des événements de manière
    synchrone ou asynchrone
    à travers un flux d’événements

    View Slide

  25. View Slide

  26. Map ( ⃝ →
    ⬛)

    View Slide

  27. View Slide

  28. View Slide

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

    View Slide

  30. View Slide

  31. Grâce à RxJava

    View Slide

  32. Écrire du code asynchrone : 

    ça craint

    View Slide

  33. Il était une fois…

    View Slide

  34. Création des 

    Reactive Extensions
    Création de RxJava
    Participation active
    Reprise de 

    RxJava & RxJava 2
    Création de Reactor
    Participation à Reactor

    View Slide

  35. RxJava 

    est une technologie 

    éprouvée

    View Slide

  36. RxJava

    profite des bonnes idées de 

    Reactor
    (et vice versa)

    View Slide

  37. Émergence 

    de différentes approches

    View Slide

  38. 2
    Reactive Streams

    View Slide

  39. Reactive Streams
    API Reactive Streams
    RxJava 2 Reactor
    Interface
    Implémentation

    View Slide

  40. L’API Reactive Streams est 

    un pont 

    entre les implémentations

    View Slide

  41. RxJava 2 est
    une implémentation
    de Reactive Streams

    View Slide

  42. RxJava n’est
    pas compatible 

    avec Reactive Streams
    (il faut alors utiliser un adapteur : RxJavaReactiveStreams)
    https://github.com/ReactiveX/RxJavaReactiveStreams

    View Slide

  43. onNext * ( onError | onComplete )

    onNext * ( onError | onCompleted )
    RxJava
    Reactive Streams

    View Slide

  44. onNext * ( onError | onComplete )

    onNext * ( onError | onCompleted )
    RxJava
    Reactive Streams
    Nom différent

    View Slide

  45. On en reparlera plus tard

    View Slide

  46. Types d’objet

    View Slide

  47. Observable

    View Slide

  48. View Slide

  49. View Slide

  50. View Slide

  51. View Slide

  52. View Slide

  53. Single

    View Slide

  54. View Slide

  55. Completable

    View Slide

  56. View Slide

  57. RxJava
    Contrat Backpressure
    Observable [N] Oui
    Single [1] Non
    Completable [0] Non
    Ajouté après coup
    Appel Web
    service
    Processus
    d’arrière plan

    View Slide

  58. É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 ?

    View Slide

  59. É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 ?

    View Slide

  60. É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 ?

    View Slide

  61. É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 ?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  68. Maybe

    View Slide

  69. View Slide

  70. Backpressure
    avec RxJava 2

    View Slide

  71. Consommateur

    View Slide

  72. Consommateur
    ça déborde !

    View Slide

  73. backpressure

    View Slide

  74. MissingBackpressureException ?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  80. Types d’objets et

    Reactive Streams

    View Slide

  81. Publisher
    Flux Flowable
    Reactive Streams

    View Slide

  82. Flux.range(1, 10)

    .flatMap(i -> Flux.just(1))

    .subscribe();

    View Slide

  83. Flux.range(1, 10)

    .flatMap(i -> Flux.just(1))

    .subscribe();
    Publisher

    View Slide

  84. Flux.range(1, 10)

    .flatMap(i -> Flowable.just(1))

    .subscribe();
    Publisher
    RxJava 2

    View Slide

  85. Flowable.defer(() -> Flux.range(1, 10))

    .subscribe(System.out::println);
    RxJava 2 Reactor

    View Slide

  86. Flux.defer(() -> Flowable.range(1, 10))

    .subscribe(System.out::println);
    RxJava 2
    Reactor

    View Slide

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

    View Slide

  88. Opérateurs

    View Slide

  89. Catalogue
    conséquent et homogène

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  97. L’ensemble des opérateurs
    couvre
    de nombreuses situations

    View Slide

  98. Nota bene

    View Slide

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

    View Slide

  100. Écrire un opérateur avec RxJava 2 est
    plus complexe
    qu’avec RxJava

    View Slide

  101. Asynchrone
    gestion de contexte d’exécution

    View Slide

  102. Schedulers
    Rethink cette partie là

    View Slide

  103. Scheduler 

    (Pool de Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  104. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  105. Tâche 1 Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  106. Tâche 1 Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  107. Tâche 1 Tâche 2
    Tâche 3 Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  108. Tâche 1
    Tâche 2
    Tâche 3 Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  109. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  110. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  111. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  112. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  113. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  114. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  115. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  116. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  117. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  118. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  119. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  120. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  121. java.lang.IllegalStateException: 

    Not on the main thread
    NetworkOnMainThreadException

    View Slide

  122. 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();

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  130. Backpressure

    View Slide

  131. Consommateur
    ça déborde !

    View Slide

  132. Flowable.range(1, 100000)

    .subscribe(new Subscriber() {


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

    }

    });

    View Slide

  133. Flowable.range(1, 100000)

    .subscribe(new Subscriber() {


    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

    View Slide

  134. Flowable.range(1, 100000)

    .subscribe(new Subscriber() {


    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

    View Slide

  135. Flowable.range(1, 100000)

    .subscribe(new Subscriber() {


    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

    View Slide

  136. source()

    .subscribe(new Subscriber() {


    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

    View Slide

  137. Rendre son application
    Reactive

    View Slide

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

    View Slide

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

    View Slide

  140. Reactive
    Reactive
    API Synchrone
    Callback
    Reactive
    Reactive

    View Slide

  141. Utilisation de
    Factory

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  146. Flowable.fromCallable(() -> computeValue())

    .subscribe(System.out::println);

    View Slide

  147. Flowable.fromCallable(() -> computeValue())

    .subscribe(System.out::println);
    Création d’une valeur
    tardive

    View Slide

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

    View Slide

  149. Observable.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

    View Slide

  150. Flowable.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

    View Slide

  151. Migrer son application
    RxJava

    View Slide

  152. Reactive Streams
    n’ acceptent pas
    de valeur null
    (sauf Maybe.fromCallable)

    View Slide

  153. Observable.fromCallable(() -> {

    voidMethod();

    return null;

    }).subscribe();
    RxJava
    Contrainte technique
    de compilation

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  157. Disposable abonnement = observeClicks()

    .map(evt -> "click !")

    .subscribe();


    CompositeDisposable abonnements = new CompositeDisposable(abonnement);


    abonnements.clear();
    Subscription → Disposable
    CompositeSubscription → CompositeDisposable

    View Slide

  158. Est-ce que
    ça va faire mal ?

    View Slide

  159. rx.Observable io.reactivex.Observable
    rx.Single
    rx.Completable io.reactivex.Completable
    io.reactivex.Single
    RxJava RxJava 2
    package différent

    View Slide

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

    View Slide

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

    View Slide

  162. Observable.interval(1, TimeUnit.SECONDS)

    .map(i -> String.valueOf(i))

    .subscribe();

    View Slide

  163. Observable.interval(1, TimeUnit.SECONDS)

    .map(i -> String.valueOf(i))

    .subscribe();
    java.util.concurrent.TimeUnit

    View Slide

  164. Observable.interval(1, TimeUnit.SECONDS)

    .map(i -> String.valueOf(i))

    .subscribe();
    io.reactivex.functions.Function

    View Slide

  165. Gestion
    des erreurs

    View Slide

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

    View Slide

  167. RxJavaPlugins.setErrorHandler(Functions.emptyConsumer());
    Peut être défini au runtime
    Gestion d’erreur par défaut

    View Slide

  168. Debug
    Rajouter stack insignifiant

    View Slide

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

    View Slide

  170. 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();

    View Slide

  171. enableTracing n’est
    pas encore supporté
    par RxJava 2
    (pour cela, il faut utiliser RxJava2Extensions)
    https://github.com/akarnokd/RxJava2Extensions

    View Slide

  172. Attention
    dégradation des
    performances !

    View Slide

  173. Performance

    View Slide

  174. Génération
    3 4 5+
    Fusion
    RxJava 2
    Reactor

    View Slide

  175. Attention
    Slides conceptuels

    View Slide

  176. Sans fusion

    View Slide

  177. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  178. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  179. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  180. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  181. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  182. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  183. Avec fusion

    View Slide

  184. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  185. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  186. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  187. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  188. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  189. La fusion
    diminue
    la consommation mémoire et
    augmente
    les performances

    View Slide

  190. for (int x = 0; x < 10_000; x++) {


    Observable.interval(10, TimeUnit.MILLISECONDS)

    .takeWhile(i -> take.get())

    .flatMap(i -> Observable.range(1, 100))

    .subscribe();

    }

    View Slide

  191. RxJava 2 RxJava
    Reactor

    View Slide

  192. http://akarnokd.blogspot.fr/2016/12/the-reactive-scrabble-benchmarks.html
    Stream Java 8
    RxJava 2 / Reactor
    RxJava
    Décembre 2016

    View Slide

  193. Stream Java 8
    RxJava 2 / Reactor
    RxJava
    https://twitter.com/akarnokd/status/844555409012740096
    Mars 2017

    View Slide

  194. RxJava 2 : 

    streams performants
    pour Android

    View Slide

  195. Ecosystème

    View Slide

  196. View Slide

  197. View Slide

  198. RxJava RxJava 2
    Retrofit Oui Oui
    RxAndroid Oui Oui
    Realm Oui Non

    View Slide

  199. We are aggressively 

    migrating our internal code to
    RxJava 2
    https://github.com/uber/AutoDispose

    View Slide

  200. Android
    RxJava

    View Slide

  201. Android
    RxJava 2

    View Slide

  202. Merci pour votre attention
    On reste en contact ?
    [email protected]
    @dwursteisen
    http://blog.soat.fr
    RefCard RxJava 2 bientôt disponible !

    View Slide