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

RxJava Training

QuickBird
September 09, 2018

RxJava Training

These are the slides from a two-day RxJava workshop we did for a group of Java-developers. RxJava is introduced with simple pictures and concepts for people who never worked with it before. In the second part of the workshop, we dive into more advanced concepts.

QuickBird

September 09, 2018
Tweet

More Decks by QuickBird

Other Decks in Programming

Transcript

  1. Training Agenda • Part 1: RxJava Background and Overview •

    Part 2: RxJava Basics • Part 3: RxJava Operators • Part 4: Example of a modern UI architecture with RxJava • Part 5: Testing with RxJava • Part 6: RxJava Advanced Malte Bucksch 2
  2. Training Agenda • Part 1: RxJava Background and Overview •

    Part 2: RxJava Basics • Part 3: RxJava Operators • Part 4: Example of a modern UI architecture with RxJava • Part 5: Testing with RxJava • Part 6: RxJava Advanced Malte Bucksch 8
  3. Part 1: Rx(Java) Background and Overview 1. Problem 2. What

    is Functional Reactive Programming (FRP)? 3. Why RxJava? 4. RxJava Basics 5. Exercise Malte Bucksch 9
  4. Fetching search results button.setOnClickListener(view -> networkClient.fetchSearchResults(query, (results, error) -> {

    if (error != null) showError(error); else showResults(results); }) ); Malte Bucksch 13
  5. Fetching search results button.setOnClickListener(view -> { new Thread(() -> networkClient.fetchSearchResults(query,

    (results, error) -> { if (error != null) showError(error); else showResults(results); }) ).start(); }); Malte Bucksch 14
  6. Fetching search results button.setOnClickListener(view -> { new Thread(() -> networkClient.fetchSearchResults(query,

    (results, error) -> { runOnUiThread(() -> { if (error != null) showError(error); else showResults(results); }); }) ).start(); }); Malte Bucksch 15
  7. Stream for data in Motion – Example: Email input Malte

    Bucksch 23 Filter (isEmailValid) Map (firstEmailPart) Subscriber Keyboard Input [email protected] malte “[email protected]”  “name” test 1234
  8. History Lesson • ReactiveX developed by Microsoft (2010) • First

    Rx Extensions library: Rx.NET • Jafar Husain (Microsoft) switched to Netflix • Evangalized Rx • Wanted to simplify threading • Netflix published RxJava (2013) • RxJava found its way from servers to clients Malte Bucksch 24 Erik Meijer, 2010
  9. Functional programming f(input) = output • Everything is a mathematic

    function • Result of function depends ONLY on the input Malte Bucksch 27 Code becomes more predictable
  10. Stream for data in Motion – Example: Email input Malte

    Bucksch 28 Filter (isEmailValid) Map (firstEmailPart) Subscriber Keyboard Input [email protected] tom test 1234
  11. Example: Imperative programming b = 1 c = 1 a

    := b + c // a = 2 c = 2 // a = 2 Malte Bucksch 34 Does NOT change when b or c change
  12. Example: Reactive programming b = 1 c = 1 a

    := b + c // a = 2 c = 2 // a = 3 Malte Bucksch 35 DOES change when b or c change
  13. Everything is a Stream Malte Bucksch 36 UI events Network

    requests Database Operations Processing operations
  14. Rx is cross-platform • Target area • Front end •

    Back end • Programming languages • RxJava • RxSwift • RxKotlin • RxJS • … Malte Bucksch 42
  15. Why Rx? • Conciseness • Fluent interface • Lazy evaluation

    • Easy concurrency • Async Error Handling Malte Bucksch 43
  16. Double clicks with RxJava Malte Bucksch 48 Observable<Object> clicks =

    RxView.clicks(button); clicks.buffer(clicks.debounce(1, TimeUnit.SECONDS)) …
  17. Double clicks with RxJava Malte Bucksch 49 Observable<Object> clicks =

    RxView.clicks(button); clicks.buffer(clicks.debounce(1, TimeUnit.SECONDS)) .filter(list -> list.size() == 2) …
  18. Double clicks with RxJava Malte Bucksch 50 Observable<Object> clicks =

    RxView.clicks(button); clicks.buffer(clicks.debounce(1, TimeUnit.SECONDS)) .filter(list -> list.size() == 2) .subscribe(size -> System.out.println("Double click!"));
  19. Double clicks: Imperative style Malte Bucksch 52 private long lastClickTime

    = 0; … button.setOnClickListener(v -> { long clickTime = System.currentTimeMillis(); if (clickTime - lastClickTime < 1000) { System.out.println("Double click!"); lastClickTime = 0; } else { lastClickTime = clickTime; } });
  20. Pull vs. Push Pull-based (Imperative Programming) • You pull the

    data once you decided that you need it • You often block the current thread when pulling • You wait until a whole operation is finished before you act on the result Malte Bucksch 54 Push-based (Reactive Programming) • You react when new data is “pushed” • You never actively wait for a result • Data is continuously pushed without waiting for the whole to complete
  21. Setup 57 WLAN: Eppleton 7692 8695 7707 6230 8360 1.

    Run the example-login-app on a phone 2. Run the unit test folder by right-clicking on the test folder Malte Bucksch
  22. Führe alle Tests aus und stell sicher, dass alle Tests

    fehlschlagen Run Tests in ‘basics_exercises’ Rechtsklick… Malte Bucksch 61 app\src\test\java\com\quickbirdstudios\ kotlintrainingexercises\basics_exercises
  23. Subscribe to Observable with an Observer Malte Bucksch 67 Observable<Point>

    mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(new Observer<Point>() { });
  24. Subscribe to Observable with an Observer Malte Bucksch 68 Observable<Point>

    mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(new Observer<Point>() { @Override public void onNext(Point location) { System.out.println("Click at location: "+location); } });
  25. Subscribe to Observable with an Observer Malte Bucksch 69 Observable<Point>

    mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(new Observer<Point>() { @Override public void onNext(Point location) { System.out.println("Click at location: "+location); } @Override public void onError(Throwable e) { System.out.println("Connection problems!"); } });
  26. Subscribe to Observable with an Observer Malte Bucksch 70 Observable<Point>

    mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(new Observer<Point>() { @Override public void onNext(Point location) { System.out.println("Click at location: "+location); } @Override public void onError(Throwable e) { System.out.println("Connection problems!"); } @Override public void onComplete() { System.out.println("Did you disconnect the mouse?"); } });
  27. Subscribe to Observable with an Observer Malte Bucksch 71 Observable<Point>

    mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(new Observer<Point>() { @Override public void onSubscribe(Disposable d) { System.out.println("New subscriber!"); } @Override public void onNext(Point location) { System.out.println("Click at location: "+location); } @Override public void onError(Throwable e) { System.out.println("Connection problems!"); } @Override public void onComplete() { System.out.println("Did you disconnect the mouse?"); } });
  28. Subscribe to Observable with a single consumer Malte Bucksch 73

    Observable<Point> mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(location -> { System.out.println("Click at location: "+location); }); onNext(Location)-Consumer
  29. Categories of Operators • Creating operators (e.g. create, just, range)

    • Filtering operators (e.g. filter, take) • Reducing operators (e.g. reduce, contains, count) • Transforming operators (e.g. map, flatMap) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Threading operators (e.g. subscribeOn, observeOn) • Error handling operators (e.g. onErrorReturn, retry) … Malte Bucksch 75
  30. Filter Example Malte Bucksch 77 Observable<Integer> intObservable = Observable.just(1,2,3,4,5); intObservable.filter(val

    -> val % 2 == 0) .subscribe(i -> { // Will receive the following values in order: 6, 12 });
  31. Map in RxJava Malte Bucksch 80 Observable<Integer> intObservable = Observable.just(1,

    2, 3, 4); intObservable.map(val -> val * 10).subscribe(i -> { // Will receive the following values in order: 10, 20, 30, 40 });
  32. Imperative vs Declarative Programming How vs What Malte Bucksch 81

    In order to do that, let’s first do THIS But don’t forget about THAT True! And in the end let’s finish with THIS I DON’T CARE HOW, JUST DO IT!
  33. RxJava Example: Getting users with a blog Malte Bucksch 82

    public List<User> getUsersWithABlog(List<User> users) { }
  34. RxJava Example: Getting users with a blog Malte Bucksch 83

    public List<User> getUsersWithABlog(List<User> users) { List<User> filteredUsers = new ArrayList<>(); for (User user : users) { if (user.hasBlog()) { filteredUsers.add(user); } } return filteredUsers; }
  35. RxJava Example: Getting users with a blog Malte Bucksch 84

    public Observable<User> getUsersWithABlog(List<User> users) { }
  36. RxJava Example: Getting users with a blog Malte Bucksch 85

    public Observable<User> getUsersWithABlog(List<User> users) { return Observable.fromIterable(users) .filter(user -> user.hasBlog()) }
  37. Rx-Libraries • RxBinding • RxPermissions • RxLifecycle • RxAnimations •

    RxLocation • RxPaparazzo • … Malte Bucksch 86
  38. Example of Rx-Library: RxBinding Malte Bucksch 87 saveButton.setOnClickListener(v -> {

    ... }); emailEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { } }); Standard way
  39. Example of Rx-Library: RxBinding Malte Bucksch 89 RxTextView.textChanges(emailEditText) .filter(this::isValid) .subscribe(newText

    -> ...); RxView.clicks(saveButton) .subscribe(view -> ...); Ignore invalid Email-Inputs
  40. Example of Rx-Library: RxBinding Malte Bucksch 90 RxTextView.textChanges(emailEditText) .map(newText ->

    newText.toString().trim()) .distinctUntilChanged() .subscribe(newText -> ...); RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  41. Example of Rx-Library: RxBinding Malte Bucksch 91 RxTextView.textChanges(emailEditText) // “Haus”

    -> .map(newText -> newText.toString().trim()) // .distinctUntilChanged() // .subscribe(newText -> ...); // RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  42. Example of Rx-Library: RxBinding Malte Bucksch 92 RxTextView.textChanges(emailEditText) // “Haus”

    -> .map(newText -> newText.toString().trim()) // “Haus” -> .distinctUntilChanged() // .subscribe(newText -> ...); // RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  43. Example of Rx-Library: RxBinding Malte Bucksch 93 RxTextView.textChanges(emailEditText) // “Haus”

    -> .map(newText -> newText.toString().trim()) // “Haus” -> .distinctUntilChanged() // “Haus” -> .subscribe(newText -> ...); // RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  44. Example of Rx-Library: RxBinding Malte Bucksch 94 RxTextView.textChanges(emailEditText) // “Haus”

    -> .map(newText -> newText.toString().trim()) // “Haus” -> .distinctUntilChanged() // “Haus” -> .subscribe(newText -> ...); // “Haus” -> RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  45. Example of Rx-Library: RxBinding Malte Bucksch 95 RxTextView.textChanges(emailEditText) // “Haus_”

    -> .map(newText -> newText.toString().trim()) // .distinctUntilChanged() // .subscribe(newText -> ...); // RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  46. Example of Rx-Library: RxBinding Malte Bucksch 96 RxTextView.textChanges(emailEditText) // “Haus_”

    -> .map(newText -> newText.toString().trim()) // “Haus” -> .distinctUntilChanged() // .subscribe(newText -> ...); // RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  47. Example of Rx-Library: RxBinding Malte Bucksch 97 RxTextView.textChanges(emailEditText) // “Haus_”

    -> .map(newText -> newText.toString().trim()) // “Haus” -> .distinctUntilChanged() // X (filtered) .subscribe(newText -> ...); // RxView.clicks(saveButton) .subscribe(view -> ...); Ignore irrelevant changes (like adding a space)
  48. Testing async code without RxJava Malte Bucksch 99 void multiplyLargeSet(List<Integer>

    numbers, int times, Callback callback) // multiplyLargeSet(numbers = [1,2,3], times = 3) -> [3,6,9]
  49. Testing async code without RxJava Malte Bucksch 100 @Test public

    void testMultiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when // then }
  50. Testing async code without RxJava Malte Bucksch 101 @Test public

    void testMultiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when multiplyLargeList(numbers, 2, multipliedNumbers -> { … }); // then }
  51. Testing async code without RxJava Malte Bucksch 102 @Test public

    void testMultiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when multiplyLargeList(numbers, 2, multipliedNumbers -> { … }); // then assertEquals(2, (int) multipliedNumbers.get(0)); assertEquals(4, (int) multipliedNumbers.get(1)); assertEquals(6, (int) multipliedNumbers.get(2)); }
  52. Testing async code without RxJava Malte Bucksch 103 @Test public

    void testMultiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when multiplyLargeList(numbers, 2, multipliedNumbers -> { … }); // then assertEquals(2, (int) multipliedNumbers.get(0)); assertEquals(4, (int) multipliedNumbers.get(1)); assertEquals(6, (int) multipliedNumbers.get(2)); } How to access this async callback’s parameter?
  53. Testing async code without RxJava Malte Bucksch 104 @Test public

    void testMultiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when List<Integer> doubledNumbers = new ArrayList<>(); multiplyLargeList(numbers, 2, multipliedNumbers -> { doubledNumbers.addAll(multipliedNumbers); }); // then assertEquals(2, (int) doubledNumbers.get(0)); assertEquals(4, (int) doubledNumbers.get(1)); assertEquals(6, (int) doubledNumbers.get(2)); }
  54. Testing async code without RxJava Malte Bucksch 105 @Test public

    void testMultiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when CountDownLatch mutex = new CountDownLatch(1); List<Integer> doubledNumbers = new ArrayList<>(); multiplyLargeList(numbers, 2, multipliedNumbers -> { doubledNumbers.addAll(multipliedNumbers); mutex.countDown(); }); mutex.await(); // then assertEquals(2, (int) doubledNumbers.get(0)); assertEquals(4, (int) doubledNumbers.get(1)); assertEquals(6, (int) doubledNumbers.get(2)); }
  55. Testing async code with RxJava Malte Bucksch 107 @Test public

    void multiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when // then }
  56. Testing async code with RxJava Malte Bucksch 108 @Test public

    void multiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when Observable<Integer> doubledNumbers = multiplyLargeList(numbers, 2); // then }
  57. Testing async code with RxJava Malte Bucksch 109 @Test public

    void multiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when Observable<Integer> doubledNumbers = multiplyLargeList(numbers, 2); // then doubledNumbers.test().assertValues(2, 4, 6); }
  58. Loosing the fear of asynchronous code Malte Bucksch 110 “We

    always thought asynchronous code must be clunky and error-prone. Since we got to know RxJava we live our life in peace.”
  59. Hacking: RxConsole • TASK: Open “exercises/exercise0_rxconsole/UserInputExercise” and resolve all TODOs

    HINT: How to execute plain Java-code in Android-Studio (right-click on the file): Malte Bucksch 114
  60. In a perfect Rx-world: No callbacks, No listeners Malte Bucksch

    117 button.setOnClickListener(v -> { //... }); networkClient.searchCafePlaces("Starbucks", cafe -> { //... });
  61. In a perfect Rx-world: No callbacks, No listeners Malte Bucksch

    118 RxView.clicks(button) .subscribe(view -> { // ... }); rxNetworkClient.searchNearbyCafePlaces("Starbucks") .subscribe(cafes -> { // ... });
  62. In a perfect Rx-world: No callbacks, No listeners Malte Bucksch

    119 RxView.clicks(button) .filter(…) .subscribe(view -> { // ... }); rxNetworkClient.searchNearbyCafePlaces("Starbucks") .map(…) .subscribe(cafes -> { // ... });
  63. Summary • RxJava is library for implementing Functional Reactive Programming

    (FRP) • ReactiveX is a cross-platform specification • RxJava makes it easier to deal with asynchronous data flows • RxJava make asynchronous code safer by applying principles from functional and declarative programming • In RxJava everything is a stream of values that can be observed • RxJava’s Power is based on its wide range of operators Malte Bucksch 121
  64. Training Agenda • Part 1: RxJava Background and Overview •

    Part 2: RxJava Basics • Part 3: RxJava Operators • Part 4: Example of a modern UI architecture with RxJava • Part 5: Testing with RxJava • Part 6: RxJava Advanced Malte Bucksch 1
  65. Most common ways to create Observables • Observable.just(…) • Observable.from…

    (e.g. fromIterable, fromArray, fromFuture) • Observable.create(…) • Observable.range(int start, int count) • Observable.empty() / Observable.never() / Observable.error(…) • Observable.generate(…) • Observable.interval(…) • Observable.timer(…) Malte Bucksch 6
  66. Most common ways to create Observables • Observable.just(…) • Observable.from…

    (e.g. fromIterable, fromArray, fromFuture) • Observable.create(…) • Observable.range(int start, int count) • Observable.empty() / Observable.never() / Observable.error(…) • Observable.interval(…) • Observable.timer(…) • Observable.generate(…) Malte Bucksch 7
  67. Creating Observables from values: Just Malte Bucksch 8 Observable.just(1, 2,

    3).subscribe(val -> { // val will be 1, 2, 3 }); 3 - 2 - 1
  68. Creating Observables from Arrays Malte Bucksch 10 int[] intArray =

    {1, 2, 3}; Observable.fromArray(intArray).subscribe(val -> { // val will be 1, 2, 3 });
  69. Creating Observables from Iterables Malte Bucksch 11 List<Integer>integerList = new

    ArrayList<>(); integerList.add(1); integerList.add(2); integerList.add(3); Observable.fromIterable(integerList).subscribe(val -> { // val will be 1, 2, 3 });
  70. Creating Observables via an Emitter Malte Bucksch 13 Observable.<Integer>create(emitter ->

    { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); }).subscribe(val -> { // val will be 1, 2, 3 });
  71. Creating observables via an Emitter Malte Bucksch 14 Observable.<Integer>create(emitter ->

    { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onError(new IllegalStateException( "Strange things did happen here...")); }).subscribe(val -> { // val will be 1, 2, 3 }, error -> { // error object after all values were emitted });
  72. Creating observables via an Emitter Malte Bucksch 15 Observable.<Integer>create(emitter ->

    { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onComplete(); }).subscribe(val -> { // val will be 1,2,3 }, throwable -> { // NO errors }, () -> { // onComplete called at the end });
  73. You can throw elements, an error or a completion-event into

    the pipe Malte Bucksch 16 3 - 2 - 1 Observable.<Integer>create(emitter -> { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onError(new IllegalStateException( "Strange things did happen here...")); })
  74. Operators create new Observables Malte Bucksch 19 Take(2) Map Completion

    after 2 elements Observable Observable 3 - 2 - 1 3 - 2 - 1 2 - 1 2x - 1y
  75. More ways to create Observables • Observable.just(…) • Observable.from… (e.g.

    fromIterable, fromArray, fromFuture) • Observable.create(…) • Observable.range(int start, int count) • Observable.empty() / Observable.never() / Observable.error(Throwable exception) • Observable.interval(…) • Observable.generate(…) • Observable.timer(…) Malte Bucksch 20
  76. Questions? • Observable.just(…) • Observable.from… (e.g. fromIterable, fromArray, fromFuture) •

    Observable.create(…) • Observable.range(int start, int count) • Observable.empty() / Observable.never() / Observable.error(…) • Observable.interval(…) • Observable.timer(…) • Observable.generate(…) Malte Bucksch 22
  77. Subscribe to Observable with an Observer Malte Bucksch 26 Observable<Point>

    mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(new Observer<Point>() { @Override public void onSubscribe(Disposable d) { System.out.println("New subscriber!"); } @Override public void onNext(Point location) { System.out.println("Click at location: "+location); } @Override public void onError(Throwable e) { System.out.println("Connection problems!"); } @Override public void onComplete() { System.out.println("Did you disconnect the mouse?"); } });
  78. Subscribe to Observable with a single consumer Malte Bucksch 27

    Observable<Point> mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(location -> { System.out.println("Click at location: “ + location); });
  79. Subscribe to Observable with a multiple consumers Malte Bucksch 28

    Observable<Point> mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(location -> { System.out.println("Click at location: " + location); }, throwable -> { // onError );
  80. Subscribe to Observable with a multiple consumers Malte Bucksch 29

    Observable<Point> mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(location -> { System.out.println("Click at location: " + location); }, throwable -> { // onError }, () -> { // onComplete });
  81. Subscribe to Observable with a multiple consumers Malte Bucksch 30

    Observable<Point> mouseClicks = receiveMouseClicks(); mouseClicks.subscribe(location -> { System.out.println("Click at location: " + location); }, throwable -> { // onError }, () -> { // onComplete }, disposable -> { // onSubscribe });
  82. Which methods are called in which order? Case 1: Two

    coffee places where found Malte Bucksch 32 NetworkClient networkClient = new NetworkClient(); networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(new Observer<Cafe>() { @Override public void onSubscribe(Disposable d) { ... } @Override public void onNext(Cafe cafe) { ... } @Override public void onError(Throwable e) { ... } @Override public void onComplete() { ... } }); #1 #2 (2x) #3
  83. Which methods are called in which order? Case 2: No

    coffee place is found Malte Bucksch 33 NetworkClient networkClient = new NetworkClient(); networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(new Observer<Cafe>() { @Override public void onSubscribe(Disposable d) { ... } @Override public void onNext(Cafe cafe) { ... } @Override public void onError(Throwable e) { ... } @Override public void onComplete() { ... } }); #1 #2
  84. Which methods are called in which order? Case 3: There

    is no internet connection Malte Bucksch 34 NetworkClient networkClient = new NetworkClient(); networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(new Observer<Cafe>() { @Override public void onSubscribe(Disposable d) { ... } @Override public void onNext(Cafe cafe) { ... } @Override public void onError(Throwable e) { ... } @Override public void onComplete() { ... } }); #1 #2
  85. Subscription callbacks onSubscribe: for every new subscriber onNext: for every

    new value onError: once after an error XOR onComplete: once after completion Malte Bucksch 35
  86. Which notifications do you get? Case 1: Two coffee places

    where found Malte Bucksch 36 networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(cafe -> { ... }); onNext, onComplete, onError, onSubscribe ?
  87. Solution Case 1: Two coffee places where found Malte Bucksch

    37 networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(cafe -> { ... }); onNext (2x), onComplete, onError, onSubscribe c
  88. Which notifications do you get? Case 2: No coffee places

    where found Malte Bucksch 38 networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(cafe -> { ... }); onNext, onComplete, onError, onSubscribe ?
  89. Solution Case 2: No coffee places where found Malte Bucksch

    39 networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(cafe -> { ... }); onNext, onComplete, onError, onSubscribe NOTHING
  90. Which notifications do you get? Case 2: No coffee places

    where found Malte Bucksch 40 networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(cafe -> { ... }, throwable -> { ... }, () -> { ... }); onNext, onComplete, onError, onSubscribe ?
  91. Solution Case 2: No coffee places where found Malte Bucksch

    41 networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(cafe -> { ... }, throwable -> { ... }, () -> { ... }); onNext, onComplete (1x), onError, onSubscribe
  92. Which notifications do you get? Case 3: No internet connection

    Malte Bucksch 42 networkClient.findNearbyCoffeePlaces("Starbucks") .subscribe(cafe -> { ... }); onNext, onComplete, onError, onSubscribe ?
  93. Disposing subscriptions Malte Bucksch 47 private Disposable disposable; … Observable<Point>

    mouseClicks = receiveMouseClicks(); disposable = mouseClicks.subscribe(location -> { System.out.println("Click at location: " + location); });
  94. Disposing subscriptions Malte Bucksch 48 private Disposable disposable; … Observable<Point>

    mouseClicks = receiveMouseClicks(); disposable = mouseClicks.subscribe(location -> { System.out.println("Click at location: " + location); }); … @Override protected void onDestroy() { disposable.dispose(); super.onDestroy(); }
  95. Cold Observables Malte Bucksch 52 Observable<String> observable = Observable.just("A", "B",

    "C", "D", "E"); // observer 1 observable.subscribe(val -> { }); // observer 2 observable.subscribe(val -> { });
  96. Cold Observables Malte Bucksch 53 Observable<String> observable = Observable.just("A", "B",

    "C", "D", "E"); // observer 1 observable.subscribe(val -> { // "A", "B", "C", "D", "E" will be received in order }); // observer 2 observable.subscribe(val -> { });
  97. Cold Observables Malte Bucksch 54 Observable<String> observable = Observable.just("A", "B",

    "C", "D", "E"); // observer 1 observable.subscribe(val -> { // "A", "B", "C", "D", "E" will be received in order }); // observer 2 observable.subscribe(val -> { // What do I receive? });
  98. Cold Observables Malte Bucksch 55 Observable<String> observable = Observable.just("A", "B",

    "C", "D", "E"); // observer 1 observable.subscribe(val -> { // "A", "B", "C", "D", "E" will be received in order }); // observer 2 observable.subscribe(val -> { // Again, "A", "B", "C", "D", "E" will be received in order });
  99. Cold Observables Malte Bucksch 58 Observable<String> observable = Observable.just("A", "B",

    "C", "D", "E"); // observer 1 observable.subscribe(val -> { // "A", "B", "C", "D", "E" will be received in order });
  100. Cold Observables Malte Bucksch 59 Observable<String> observable = Observable.just("A", "B",

    "C", "D", "E"); // observer 1 observable.subscribe(val -> { // "A", "B", "C", "D", "E" will be received in order }); // observer 2 observable.subscribe(val -> { // Again, "A", "B", "C", "D", "E" will be received in order });
  101. Cold creates & listens to Producer, Hot only listens to

    Producer Malte Bucksch 64 // COLD Observable<Object> cold = Observable.create(emitter -> { });
  102. Cold creates & listens to Producer, Hot only listens to

    Producer Malte Bucksch 65 // COLD Observable<Object> cold = Observable.create(emitter -> { Producer producer = new Producer(); producer.addListener(newProducerValue -> { emitter.onNext(newProducerValue); }); });
  103. Cold creates & listens to Producer, Hot only listens to

    Producer Malte Bucksch 66 // COLD Observable<Object> cold = Observable.create(emitter -> { Producer producer = new Producer(); producer.addListener(newProducerValue -> { emitter.onNext(newProducerValue); }); }); // HOT Observable<Object> hot = Observable.create(emitter -> { });
  104. Cold creates & listens to Producer, Hot only listens to

    Producer Malte Bucksch 67 // COLD Observable<Object> cold = Observable.create(emitter -> { Producer producer = new Producer(); producer.addListener(newProducerValue -> { emitter.onNext(newProducerValue); }); }); // HOT Producer producer = new Producer(); Observable<Object> hot = Observable.create(emitter -> { producer.addListener(newProducerValue -> { emitter.onNext(newProducerValue); }); });
  105. Keyboard Input Malte Bucksch 74 Producer producer = new Producer();

    Observable<Object> observable = Observable.create(emitter -> { producer.addListener(newProducerValue -> { emitter.onNext(newProducerValue); }); });
  106. Malte Bucksch 75 Observable<Object> observable = Observable.create(emitter -> { Producer

    producer = new Producer(); producer.addListener(newProducerValue -> { emitter.onNext(newProducerValue); }); });
  107. Summary: Hot vs Cold Observables Cold • Nothing happens if

    there is no Observer • Producer created for each Observer • Values are produced twice if two Observers subscribe Malte Bucksch 76 Hot • Data flows already, even if there is no Observer • Producer created once only but independent of Observers • Values are produced only once, even if two Observers subscribe
  108. Summary: Observables • You can create Observables via many different

    operators like: • Observable.create, Observable.just, Observable.from… • You can subscribe to an Observable • Via an Observer • Via one or more Consumers (short-form) Malte Bucksch 77
  109. Lifecycle Observable: onSubscribe -> onNext(value) -> onNext(value) -> … ->

    [onError XOR onComplete] Single: onSubscribe -> [onError XOR onSuccess(value)] Maybe: onSubscribe -> [onError XOR onSuccess(value) XOR onComplete] Completable: onSubscribe -> [onError XOR onComplete] Malte Bucksch 86
  110. Training Agenda • Part 1: RxJava Background and Overview •

    Part 2: RxJava Basics • Part 3: RxJava Operators • Part 4: Example of a modern UI architecture with RxJava • Part 5: Testing with RxJava • Part 6: RxJava Advanced Malte Bucksch 1
  111. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) … Malte Bucksch 5
  112. Operators Malte Bucksch 6 Observable<Integer> intObservable = Observable.create(emitter -> {

    emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onNext(4); emitter.onNext(5); emitter.onComplete(); }); intObservable .subscribe(i -> { // Will receive the following values in order: 1, 2, 3, 4, 5 });
  113. Operators Malte Bucksch 7 Observable<Integer> intObservable = Observable.create(emitter -> {

    emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onNext(4); emitter.onNext(5); emitter.onComplete(); }); intObservable.map(val -> val * 3) .subscribe(i -> { // Will receive the following values in order: 3, 6, 9, 12, 15 });
  114. Operators Malte Bucksch 8 Observable<Integer> intObservable = Observable.create(emitter -> {

    emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onNext(4); emitter.onNext(5); emitter.onComplete(); }); intObservable.map(val -> val * 3) .filter(val -> val % 2 == 0) .subscribe(i -> { // Will receive the following values in order: 6, 12 });
  115. Best practice: Use the operators Malte Bucksch 9 Observable<Integer> intObservable

    = Observable.create(emitter -> { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onNext(4); emitter.onNext(5); emitter.onComplete(); }); intObservable.subscribe(i -> { int multipliedVal = i * 3; if (multipliedVal % 2 == 0) { // Will receive the following values in order: 6, 12 } });
  116. Best practice: Use the operators Malte Bucksch 10 Observable<Integer> intObservable

    = Observable.create(emitter -> { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onNext(4); emitter.onNext(5); emitter.onComplete(); }); intObservable.subscribe(i -> { int multipliedVal = i * 3; if (multipliedVal % 2 == 0) { // Will receive the following values in order: 6, 12 } });
  117. Operators Malte Bucksch 11 Observable<Integer> intObservable = Observable.create(emitter -> {

    emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onNext(4); emitter.onNext(5); emitter.onComplete(); }); intObservable.map(val -> val * 3) .filter(val -> val % 2 == 0) .subscribe(i -> { // Will receive the following values in order: 6, 12 });
  118. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) … Malte Bucksch 22
  119. Lazy evaluation of RxJava Malte Bucksch 36 public static void

    main(String[]args){ System.out.println("Starting the system..."); }
  120. Lazy evaluation of RxJava Malte Bucksch 37 public static void

    main(String[]args){ System.out.println("Starting the system..."); Observable.<Integer>create(emitter -> { System.out.println("Starting the computation right now"); }); }
  121. Lazy evaluation of RxJava Malte Bucksch 38 public static void

    main(String[]args){ System.out.println("Starting the system..."); Observable.<Integer>create(emitter -> { System.out.println("Starting the computation right now"); int result = *crazy, expensive, complicated computation*; emitter.onNext(result); emitter.onComplete(); }); }
  122. Lazy evaluation of RxJava Malte Bucksch 39 public static void

    main(String[]args){ System.out.println("Starting the system..."); Observable.<Integer>create(emitter -> { System.out.println("Starting the computation right now"); int result = *crazy, expensive, complicated computation*; emitter.onNext(result); emitter.onComplete(); }); } What will be printed? Output: "Starting the system..."
  123. Lazy evaluation of RxJava Malte Bucksch 40 public static void

    main(String[]args) { System.out.println("Starting the system..."); Observable.<Integer>create(emitter -> { System.out.println("Starting computation…"); int result = *crazy, expensive, complicated computation *; emitter.onNext(result); emitter.onComplete(); }).subscribe(integer -> { System.out.println("Received: " + integer); }); } What will be printed? Output: "Starting the system...“ "Starting computation…“ "Received: 2332”
  124. Lazy evaluation of RxJava Malte Bucksch 42 Observable.just(1,2,3,4,5) .map(value ->

    { System.out.println("computing..."); int result = *expensive computation*; return result; })
  125. Lazy evaluation of RxJava Malte Bucksch 43 Observable.just(1,2,3,4,5) .map(value ->

    { System.out.println("computing..."); int result = *expensive computation*; return result; }) .take(2)
  126. Lazy evaluation of RxJava Malte Bucksch 44 Observable.just(1,2,3,4,5) .map(value ->

    { System.out.println("computing..."); int result = *expensive computation*; return result; }) .take(2) .subscribe(result -> { System.out.println("Received result: "+result); });
  127. Lazy evaluation of RxJava Malte Bucksch 45 Observable.just(1,2,3,4,5) .map(value ->

    { System.out.println("computing..."); int result = *expensive computation*; return result; }) .take(2) .subscribe(result -> { System.out.println("Received result: "+result); }); What will be printed? Output: computing... Received result: 1 computing... Received result: 2
  128. Questions? • filter: Filter out elements that do not meet

    a certain criteria • skip/skipLast: Skip elements from start of stream or end • take/takeLast: Take only elements from start of stream or end • distinct: Filter out elements that have been emitted before • sample: Filter out all elements except for a small subset Malte Bucksch 46
  129. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) … Malte Bucksch 47
  130. Using flatMap to communicate with Search API Malte Bucksch 53

    Please enter your search query… Café Search
  131. Using flatMap to communicate with Search API Malte Bucksch 54

    NetworkSearchClient searchClient = new NetworkSearchClient(); final Observable<String> textChanges = RxTextView.textChanges(searchField);
  132. Using flatMap to communicate with Search API Malte Bucksch 55

    NetworkSearchClient searchClient = new NetworkSearchClient(); final Observable<String> textChanges = RxTextView.textChanges(searchField); final Observable<Cafe> cozyCafes = textChanges .map(newText -> newText.trim()) …
  133. Using flatMap to communicate with Search API Malte Bucksch 56

    NetworkSearchClient searchClient = new NetworkSearchClient(); final Observable<String> textChanges = RxTextView.textChanges(searchField); final Observable<Cafe> cozyCafes = textChanges .map(newText -> newText.trim()) .flatMap(newText -> searchClient.searchCafes(newText)) Signature: Observable<Cafe> searchCafes(String searchQuery) { ... }
  134. Using flatMap to communicate with Search API Malte Bucksch 57

    NetworkSearchClient searchClient = new NetworkSearchClient(); final Observable<String> textChanges = RxTextView.textChanges(searchField); final Observable<Cafe> cozyCafes = textChanges .map(newText -> newText.trim()) .flatMap(newText -> searchClient.searchCafes(newText)) .filter(cafe -> cafe.isCozyAndWarm());
  135. Using flatMap to communicate with Search API Malte Bucksch 58

    NetworkSearchClient searchClient = new NetworkSearchClient(); final Observable<String> textChanges = RxTextView.textChanges(searchField); final Observable<Cafe> cozyCafes = textChanges .map(newText -> newText.trim()) .flatMap(newText -> searchClient.findCoffeePlaces(newText)) .filter(cafe -> cafe.isCozyAndWarm()); cozyCafes.subscribe(cafe -> System.out.print(cafe.name));
  136. Questions? • map: transform elements • flatMap: receive elements from

    a second Observable in the current Observable Malte Bucksch 61
  137. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) … Malte Bucksch 62
  138. Aggregation Operators Operators that operate on the entire sequence of

    emitted items • contains() • all() • reduce() Malte Bucksch 63
  139. Questions? • contains: check if the Observable emitted a certain

    element • all: check if ALL elements match a criteria • reduce: combine all elements one after another to single result value Malte Bucksch 79
  140. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) • … Malte Bucksch 81
  141. Questions? • merge: merge the emissions of multiple Observables into

    one • combineLatest: combine the latest emissions of multiple Observables into a combined value • zip: combine elements of multiple Observables respecting their order Malte Bucksch 99
  142. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) • … Malte Bucksch 100
  143. Questions? • delay: delay the emissions of an Observable by

    a certain time • timeout: throw error if the Observable didn’t complete in a specific time range • buffer: buffer the elements in a certain time span into a list of elements Malte Bucksch 109
  144. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) … Malte Bucksch 110
  145. Questions? • onError… • onErrorReturnItem: return a single item instead

    of emitting an error • onErrorResumeNext: subscribe to another Observable instead of emitting an error • Retry: subscribe to the same Observable again if an error was emitted Malte Bucksch 119
  146. Categories of Operators • Filtering operators (e.g. filter, take) •

    Transforming operators (e.g. map, flatMap) • Aggregation operators (e.g. reduce, contains, count) • Combining operators (e.g. merge, combineLatest) • Time based operators (e.g. buffer, delay) • Error handling operators (e.g. onErrorReturn, retry) • Threading operators (e.g. subscribeOn, observeOn) … Malte Bucksch 121
  147. Fetching search results: WITHOUT Rx button.setOnClickListener(view -> { new Thread(()

    -> networkClient.fetchSearchResults(query, (results, error) -> { runOnUiThread(() -> { if (error != null) showError(error); else showResults(results); }); }) ).start(); }); Malte Bucksch 123
  148. Fetching search results: WITH Rx RxView.clicks(button) .flatMap(view -> networkClient.fetchSearchResults(query)) .subscribeOn(Schedulers.newThread())

    .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::showResults, this::showError); Malte Bucksch 124
  149. What will be printed? Malte Bucksch 129 print("Before"); Observable.<String>create(emitter ->

    { print("Creating Observable"); emitter.onNext("test"); emitter.onComplete(); }).subscribe(new Observer<String>() { public void onSubscribe(Disposable d) { print("onSubscribe()"); } public void onNext(String value) { print("onNext(): " + value); } public void onComplete() { print("onComplete()"); } public void onError(Throwable e) { } }); print("After"); Before onSubscribe() After Creating Observable onNext(): test onComplete() A Before onSubscribe() Creating Observable onNext(): test onComplete() After B Before onSubscribe() Creating Observable After onNext(): test onComplete() C
  150. What will be printed? Malte Bucksch 130 print("Before"); Observable.<String>create(emitter ->

    { print("Creating Observable"); emitter.onNext("test"); emitter.onComplete(); }).subscribe(new Observer<String>() { public void onSubscribe(Disposable d) { print("onSubscribe()"); } public void onNext(String value) { print("onNext(): " + value); } public void onComplete() { print("onComplete()"); } public void onError(Throwable e) { } }); print("After"); Before onSubscribe() After Creating Observable onNext(): test onComplete() A Before onSubscribe() Creating Observable onNext(): test onComplete() After B Before onSubscribe() Creating Observable After onNext(): test onComplete() C
  151. What will be printed? Malte Bucksch 132 print("Before"); Observable.<String>create(emitter ->

    { print("Creating Observable"); emitter.onNext("test"); emitter.onComplete(); }) .subscribeOn(Schedulers.newThread()) .subscribe(new Observer<String>() { public void onSubscribe(Disposable d) { print("onSubscribe()"); } public void onNext(String value) { print("onNext(): " + value); } public void onComplete() { print("onComplete()"); } public void onError(Throwable e) { } }); print("After"); Before onSubscribe() After Creating Observable onNext(): test onComplete() A Before onSubscribe() Creating Observable onNext(): test onComplete() After B Before onSubscribe() Creating Observable After onNext(): test onComplete() C
  152. What will be printed? Malte Bucksch 133 print("Before"); Observable.<String>create(emitter ->

    { print("Creating Observable"); emitter.onNext("test"); emitter.onComplete(); }) .subscribeOn(Schedulers.newThread()) .subscribe(new Observer<String>() { public void onSubscribe(Disposable d) { print("onSubscribe()"); } public void onNext(String value) { print("onNext(): " + value); } public void onComplete() { print("onComplete()"); } public void onError(Throwable e) { } }); print("After"); Before onSubscribe() After Creating Observable onNext(): test onComplete() A Before onSubscribe() Creating Observable onNext(): test onComplete() After B Before onSubscribe() Creating Observable After onNext(): test onComplete() C
  153. What will be printed? Malte Bucksch 135 print("Before"); Observable.<String>create(emitter ->

    { print("Creating Observable"); emitter.onNext("test"); emitter.onComplete(); }) .observeOn(Schedulers.newThread()) .subscribe(new Observer<String>() { public void onSubscribe(Disposable d) { print("onSubscribe()"); } public void onNext(String value) { print("onNext(): " + value); } public void onComplete() { print("onComplete()"); } public void onError(Throwable e) { } }); print("After"); Before onSubscribe() After Creating Observable onNext(): test onComplete() A Before onSubscribe() Creating Observable onNext(): test onComplete() After B Before onSubscribe() Creating Observable After onNext(): test onComplete() C
  154. What will be printed? Malte Bucksch 136 print("Before"); Observable.<String>create(emitter ->

    { print("Creating Observable"); emitter.onNext("test"); emitter.onComplete(); }) .observeOn(Schedulers.newThread()) .subscribe(new Observer<String>() { public void onSubscribe(Disposable d) { print("onSubscribe()"); } public void onNext(String value) { print("onNext(): " + value); } public void onComplete() { print("onComplete()"); } public void onError(Throwable e) { } }); print("After"); Before onSubscribe() After Creating Observable onNext(): test onComplete() A Before onSubscribe() Creating Observable onNext(): test onComplete() After B Before onSubscribe() Creating Observable After onNext(): test onComplete() C
  155. Summary Malte Bucksch 137 print("Before"); Observable.<String>create(emitter -> { print("Creating Observable");

    emitter.onNext("test"); emitter.onComplete(); }) … ? .subscribe(new Observer<String>() { public void onSubscribe(Disposable d) { print("onSubscribe()"); } public void onNext(String value) { print("onNext(): " + value); } public void onComplete() { print("onComplete()"); } public void onError(Throwable e) { } }); print("After"); Before onSubscribe() After Creating Observable onNext(): test onComplete() A Before onSubscribe() Creating Observable onNext(): test onComplete() After B Before onSubscribe() Creating Observable After onNext(): test onComplete() C Standard case (no operator) .subscribeOn(Schedulers.newThread()) .obseveOn(Schedulers.newThread())
  156. Schduling tasks: Without RxJava button.setOnClickListener(view -> { new Thread(() ->

    networkClient.fetchSearchResults(query, (results, error) -> { runOnUiThread(() -> { if (error != null) showError(error); else showResults(results); }); }) ).start(); }); Malte Bucksch 138
  157. Scheduling tasks with RxJava: Abstracting the details away RxView.clicks(button) .flatMap(view

    -> networkClient.fetchSearchResults(query)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::showResults, this::showError); Malte Bucksch 139
  158. Different types of Schedulers computeSomething() .subscribeOn(Schedulers.computation()) .subscribe(result -> { });

    computeSomething() .subscribeOn(Schedulers.io()) .subscribe(result -> { }); computeSomething() .subscribeOn(Schedulers.newThread()) .subscribe(result -> { }); computeSomething() .subscribeOn(Schedulers.single()) .subscribe(result -> { }); Malte Bucksch 140
  159. Questions? • subscribeOn: execute the subscription of an Observable on

    a different thread • observeOn: execute the Observer code of an Observable on a different thread • Different types of Schedulers: newThread, io, computation, single … Malte Bucksch 141
  160. Interacting with a world outside of Rx • Using Rx

    in Non-rx code: Blocking operators • Blocking first, last … • Collection operators • toList() • toSortedList() • toMap() and toMultiMap() • collect() • Using Non-Rx Code with Rx • Adapting interfaces of Non-Rx code to Rx Malte Bucksch 143
  161. Questions? • Using Rx in Non-rx code: Blocking operators •

    Blocking first: fetch first element of Observable by blocking the thread until Observable emitted an element • Collection operators: convert Observable element emissions to a List by blocking the thread until Observable completed e.g. toList() • Using Non-Rx Code with Rx • Adapting interfaces of Non-Rx code to Rx Malte Bucksch 145
  162. Subject are Observers and Observables at the same time Malte

    Bucksch 9 PublishSubject<Object> subject = PublishSubject.create();
  163. Subject are Observers and Observables at the same time Malte

    Bucksch 10 PublishSubject<Object> subject = PublishSubject.create(); subject.subscribe(new Observer<Object>() { public void onSubscribe(Disposable d) { } public void onNext(Object o) { } public void onError(Throwable e) { } public void onComplete() { } }); Subscribing to a Subject
  164. Subject are Observers and Observables at the same time Malte

    Bucksch 11 PublishSubject<Object> subject = PublishSubject.create(); subject.subscribe(new Observer<Object>() { public void onSubscribe(Disposable d) { } public void onNext(Object o) { } public void onError(Throwable e) { } public void onComplete() { } }); otherObservable.subscribe(subject); Register Subject as an Observer
  165. Subject are Observers and Observables at the same time Malte

    Bucksch 12 PublishSubject<Object> subject = PublishSubject.create(); subject.subscribe(new Observer<Object>() { public void onSubscribe(Disposable d) { } public void onNext(Object o) { } public void onError(Throwable e) { } public void onComplete() { } }); otherObservable.subscribe(subject); subject.onNext("Value"); subject.onError(new IllegalStateException()); subject.onComplete(); Manually inserting values into the subject
  166. PublishSubject: Example Malte Bucksch 15 PublishSubject<Object> subject = PublishSubject.create(); //

    observer1 will receive all onNext and onComplete events subject.subscribe(observer1); subject.onNext("one"); subject.onNext("two");
  167. PublishSubject: Example Malte Bucksch 16 PublishSubject<Object> subject = PublishSubject.create(); //

    observer1 will receive all onNext and onComplete events subject.subscribe(observer1); subject.onNext("one"); subject.onNext("two"); subject.subscribe(observer2); subject.onNext("three"); subject.onComplete();
  168. PublishSubject: Example Malte Bucksch 17 PublishSubject<Object> subject = PublishSubject.create(); //

    observer1 will receive all onNext and onComplete events subject.subscribe(observer1); subject.onNext("one"); subject.onNext("two"); // observer2 will only receive "three" and onComplete subject.subscribe(observer2); subject.onNext("three"); subject.onComplete();
  169. BehaviorSubject: Example 1 Malte Bucksch 21 BehaviorSubject<Object> subject = BehaviorSubject.createDefault("default");

    subject.subscribe(observer); subject.onNext("one"); subject.onNext("two"); subject.onNext("three");
  170. BehaviorSubject: Example 1 Malte Bucksch 22 // observer will receive

    all 4 events (including "default"). BehaviorSubject<Object> subject = BehaviorSubject.createDefault("default"); subject.subscribe(observer); subject.onNext("one"); subject.onNext("two"); subject.onNext("three");
  171. BehaviorSubject: Example 2 Malte Bucksch 23 BehaviorSubject<Object> subject = BehaviorSubject.create();

    subject.onNext("zero"); subject.onNext("one"); subject.subscribe(observer); subject.onNext("two"); subject.onNext("three");
  172. BehaviorSubject: Example 2 Malte Bucksch 24 // observer will receive

    the "one", "two" and "three" events, but not "zero" BehaviorSubject<Object> subject = BehaviorSubject.create(); subject.onNext("zero"); subject.onNext("one"); subject.subscribe(observer); subject.onNext("two"); subject.onNext("three");
  173. BehaviorSubject: Example 3 Malte Bucksch 25 BehaviorSubject<Object> subject = BehaviorSubject.create();

    subject.onNext("zero"); subject.onNext("one"); subject.onComplete(); subject.subscribe(observer);
  174. BehaviorSubject: Example 3 Malte Bucksch 26 // observer will receive

    only onComplete BehaviorSubject<Object> subject = BehaviorSubject.create(); subject.onNext("zero"); subject.onNext("one"); subject.onComplete(); subject.subscribe(observer);
  175. BehaviorSubject: Example 4 Malte Bucksch 27 BehaviorSubject<Object> subject = BehaviorSubject.create();

    subject.onNext("zero"); subject.onNext("one"); subject.onError(new RuntimeException("error")); subject.subscribe(observer);
  176. BehaviorSubject: Example 4 Malte Bucksch 28 // observer will receive

    only onError BehaviorSubject<Object> subject = BehaviorSubject.create(); subject.onNext("zero"); subject.onNext("one"); subject.onError(new RuntimeException("error")); subject.subscribe(observer);
  177. Summary: Subject • Subjects are Observables and Observers at the

    same time • PublishSubjects is the “standard-case” emitting exactly what it observes • There are other variants like BehaviourSubjects which can come handy sometimes • Most often a Subject is NOT what you need and should be used only if you have good reasons for it Malte Bucksch 29
  178. Training Agenda • Part 1: RxJava Background and Overview •

    Part 2: RxJava Basics • Part 3: RxJava Operators • Part 4: Example of a modern UI architecture with RxJava • Part 5: Testing with RxJava • Part 6: RxJava Advanced Malte Bucksch 1
  179. Modern Architecture with RxJava: MVVM I. The problem we’re solving

    II. Basic concept of MVVM III. How to use RxJava to implement a functional reactive App- Architecture IV. Testing with MVVM and RxJava V. Reusability of ViewModels Malte Bucksch 3
  180. Malte Bucksch 4 TEAM Testable Sharing logic between Android and

    iOS Beautiful native UI Awesome app Robust & Bug-free
  181. Malte Bucksch 5 TEAM Mixing business logic and view logic

    Testable Beautiful native UI Awesome app Sharing logic between Android and iOS Robust & Bug-free
  182. “Model View Controller (MVC) is one of the most quoted

    (and most misquoted) patterns around” – Martin Fowler (martinfowler.com) Stefan Kofler & Malte Bucksch 8
  183. Common practice with MVC Stefan Kofler & Malte Bucksch 10

    View View Controller Fragment ViewController
  184. MVVM: Model-View-ViewModel Malte Bucksch 13 View View Model Model Presentation

    User Input Business Logic Data User action Update Update Notify
  185. ViewModel Interface 32 public interface TranslatorViewModel { // --- inputs

    Observer<String> inputEnglishText(); Observer<Boolean> inputSaveTrigger(); } Malte Bucksch
  186. ViewModel Interface 33 public interface TranslatorViewModel { // --- inputs

    Observer<String> inputEnglishText(); Observer<Boolean> inputSaveTrigger(); // --- outputs Observable<String> outputGermanText(); Observable<Boolean> outputIsSavingAllowed(); Observable<String> outputSavedGermanTranslation(); } Malte Bucksch
  187. ViewModel Implementation Malte Bucksch 35 public class TranslatorViewModelImpl implements TranslatorViewModel

    { private final BehaviorSubject<String> inputEnglishText = BehaviorSubject.createDefault(""); private final PublishSubject<Boolean> inputSaveTrigger = PublishSubject.create(); // --- inputs public BehaviorSubject<String> inputEnglishText() { return inputEnglishText; } public PublishSubject<Boolean> inputSaveTrigger() { return inputSaveTrigger; } }
  188. ViewModel Implementation Malte Bucksch 36 public class TranslatorViewModelImpl implements TranslatorViewModel

    { private final BehaviorSubject<String> inputEnglishText = BehaviorSubject.createDefault(""); private final PublishSubject<Boolean> inputSaveTrigger = PublishSubject.create(); // --- inputs public BehaviorSubject<String> inputEnglishText() { return inputEnglishText; } public PublishSubject<Boolean> inputSaveTrigger() { return inputSaveTrigger; } // --- outputs public Observable<String> outputGermanText() { return inputEnglishText() .map(TranslatorEngine::translateToGerman); } }
  189. ViewModel Implementation Malte Bucksch 37 public class TranslatorViewModelImpl implements TranslatorViewModel

    { private final BehaviorSubject<String> inputEnglishText = BehaviorSubject.createDefault(""); private final PublishSubject<Boolean> inputSaveTrigger = PublishSubject.create(); // --- inputs public BehaviorSubject<String> inputEnglishText() { return inputEnglishText; } public PublishSubject<Boolean> inputSaveTrigger() { return inputSaveTrigger; } // --- outputs public Observable<String> outputGermanText() { return inputEnglishText() .map(TranslatorEngine::translateToGerman); } public Observable<Boolean> outputIsSavingAllowed() { return inputEnglishText() .map(english -> !english.isEmpty()); } }
  190. ViewModel Implementation Malte Bucksch 38 public class TranslatorViewModelImpl implements TranslatorViewModel

    { private final BehaviorSubject<String> inputEnglishText = BehaviorSubject.createDefault(""); private final PublishSubject<Boolean> inputSaveTrigger = PublishSubject.create(); // --- inputs public BehaviorSubject<String> inputEnglishText() { return inputEnglishText; } public PublishSubject<Boolean> inputSaveTrigger() { return inputSaveTrigger; } // --- outputs public Observable<String> outputGermanText() { return inputEnglishText() .map(TranslatorEngine::translateToGerman); } public Observable<Boolean> outputIsSavingAllowed() { return inputEnglishText() .map(english -> !english.isEmpty()); } public Observable<String> outputSavedGermanTranslation() { return inputSaveTrigger() .withLatestFrom(outputGermanText(), (trigger, germanText) -> germanText); } }
  191. Binding to ViewModels via Java Fragment Malte Bucksch 39 //

    *** subscribe to inputs *** // *** subscribe to outputs ***
  192. Binding to ViewModels via Java Fragment Malte Bucksch 40 //

    *** subscribe to inputs *** RxTextView.textChanges(englishTextView) .subscribe(text -> translatorViewModel.inputEnglishText() .onNext(text)); // *** subscribe to outputs ***
  193. Binding to ViewModels via Java Fragment Malte Bucksch 41 //

    *** subscribe to inputs *** RxTextView.textChanges(englishTextView) .subscribe(text -> translatorViewModel.inputEnglishText() .onNext(text)); RxView.clicks(saveButton) .subscribe(v -> translatorViewModel.inputSaveTrigger() .onNext(true)); // *** subscribe to outputs ***
  194. Binding to ViewModels via Java Fragment Malte Bucksch 42 //

    *** subscribe to inputs *** RxTextView.textChanges(englishTextView) .subscribe(text -> translatorViewModel.inputEnglishText() .onNext(text)); RxView.clicks(saveButton) .subscribe(v -> translatorViewModel.inputSaveTrigger() .onNext(true)); // *** subscribe to outputs *** translatorViewModel.outputGermanText() .subscribe(germanEditText::setText);
  195. Binding to ViewModels via Java Fragment Malte Bucksch 43 //

    *** subscribe to inputs *** RxTextView.textChanges(englishTextView) .subscribe(text -> translatorViewModel.inputEnglishText() .onNext(text)); RxView.clicks(saveButton) .subscribe(v -> translatorViewModel.inputSaveTrigger() .onNext(true)); // *** subscribe to outputs *** translatorViewModel.outputGermanText() .subscribe(germanEditText::setText); translatorViewModel.outputIsSavingAllowed() .subscribe(saveButton::setEnabled); translatorViewModel.outputSavedGermanTranslation() .subscribe(this::saveToClipboard);
  196. Binding to ViewModels via Java Fragment Malte Bucksch 44 //

    *** subscribe to inputs *** RxTextView.textChanges(englishTextView) .subscribe(text -> translatorViewModel.inputEnglishText() .onNext(text)); RxView.clicks(saveButton) .subscribe(v -> translatorViewModel.inputSaveTrigger() .onNext(true)); // *** subscribe to outputs *** translatorViewModel.outputGermanText() .subscribe(germanEditText::setText); translatorViewModel.outputIsSavingAllowed() .subscribe(saveButton::setEnabled); translatorViewModel.outputSavedGermanTranslation() .subscribe(this::saveToClipboard);
  197. ViewModel Tests Malte Bucksch 47 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); // when // then }
  198. ViewModel Tests Malte Bucksch 48 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when // then }
  199. ViewModel Tests Malte Bucksch 49 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when translatorViewModel.inputEnglishText().onNext("Dog"); // then }
  200. ViewModel Tests Malte Bucksch 50 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when translatorViewModel.inputEnglishText().onNext("Dog"); // then testObserver.assertValueAt(testObserver.valueCount()-1,"Hund"); }
  201. Local unit tests for UI testing Malte Bucksch 51 Fast

    local unit tests Avoid UI testing frameworks
  202. Wrap up: MVVM • Clear separation of concerns • Slim

    Views and slim ViewModels instead of massive all-in-one class • Logic can be reused on different platforms • Functional way of writing UI with isolated side effects • Bugs often prevented • Great testability • Asynchronous code that is thread-safe Malte Bucksch 60
  203. Hacking • Task: Implement a Login-Screen using MVVM • Open

    the package “exercise6_mvvm_ui and resolve TODOs in the LoginViewModelImpl HINT: you can orient at the Translator example-ViewModel Observable.combineLatest(x,y, (lastX, lastY) -> lastX + lastY) Malte Bucksch 63
  204. Training Agenda • Part 1: RxJava Background and Overview •

    Part 2: RxJava Basics • Part 3: RxJava Operators • Part 4: Example of a modern UI architecture with RxJava • Part 5: Testing with RxJava • Part 6: RxJava Advanced Malte Bucksch 1
  205. Testing async code without RxJava Malte Bucksch 3 @Test public

    void testMultiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when CountDownLatch mutex = new CountDownLatch(1); List<Integer> doubledNumbers = new ArrayList<>(); multiplyLargeList(numbers, 2, multipliedNumbers -> { doubledNumbers.addAll(multipliedNumbers); mutex.countDown(); }); mutex.await(); // then assertEquals(2, (int) doubledNumbers.get(0)); assertEquals(4, (int) doubledNumbers.get(1)); assertEquals(6, (int) doubledNumbers.get(2)); }
  206. Testing async code with RxJava Malte Bucksch 4 @Test public

    void multiplyLargeList() { // given List<Integer> numbers = Arrays.asList(1, 2, 3); // when Observable<Integer> doubledNumbers = multiplyLargeList(numbers, 2); // then doubledNumbers.test().assertValues(2, 4, 6); }
  207. Testing with RxJava • Blocking operators • blockingSubscribe() • blockingFirst()

    • … • TestObserver • test() • Assertions • TestScheduler Malte Bucksch 5
  208. Blocking operators: blockingLast @Test public void testLast() { Observable<String> source

    = Observable.just("Alpha", "Beta", "Gamma", "Delta", "Zeta"); } Malte Bucksch 6
  209. Blocking operators: blockingLast @Test public void testLast() { Observable<String> source

    = Observable.just("Alpha", "Beta", "Gamma", "Delta", "Zeta"); String lastWithLengthFour = … assertTrue(lastWithLengthFour.equals("Zeta")); } Malte Bucksch 7
  210. Blocking operators: blockingLast @Test public void testLast() { Observable<String> source

    = Observable.just("Alpha", "Beta", "Gamma", "Delta", "Zeta"); String lastWithLengthFour = source.filter(s -> s.length() == 4) .blockingLast(); assertTrue(lastWithLengthFour.equals("Zeta")); } Malte Bucksch 8
  211. Blocking operators: blockingSubscribe @Test public void testHitCountIsFive() { Observable<Long> source

    = Observable.interval(1, TimeUnit.SECONDS) .take(5); } Malte Bucksch 9
  212. Blocking operators: blockingSubscribe @Test public void testHitCountIsFive() { AtomicInteger hitCount

    = new AtomicInteger(); Observable<Long> source = Observable.interval(1, TimeUnit.SECONDS) .take(5); assertTrue(hitCount.get() == 5); } Malte Bucksch 10
  213. Blocking operators: blockingSubscribe @Test public void testHitCountIsFive() { AtomicInteger hitCount

    = new AtomicInteger(); Observable<Long> source = Observable.interval(1, TimeUnit.SECONDS) .take(5); source.blockingSubscribe(i -> hitCount.incrementAndGet()); assertTrue(hitCount.get() == 5); } Malte Bucksch 11
  214. TestObserver: Example Malte Bucksch 14 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); // when // then }
  215. TestObserver: Example Malte Bucksch 15 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when // then }
  216. TestObserver: Example Malte Bucksch 16 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when translatorViewModel.inputEnglishText().onNext("Dog"); // then }
  217. TestObserver: Example Malte Bucksch 17 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when translatorViewModel.inputEnglishText().onNext("Dog"); // then testObserver.assertValueAt(testObserver.valueCount()-1,"Hund"); } Last value received
  218. TestObserver: Example Malte Bucksch 18 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when translatorViewModel.inputEnglishText().onNext("Dog"); // then testObserver.assertValueAt(testObserver.valueCount()-1,"Hund"); }
  219. TestObserver: Example Malte Bucksch 19 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = new TestObserver<>(); translatorViewModel.outputGermanText().subscribe(testObserver); // when translatorViewModel.inputEnglishText().onNext("Dog"); // then testObserver.assertValueAt(testObserver.valueCount()-1,"Hund"); }
  220. TestObserver: Recording Malte Bucksch 21 @Test public void testTranslation() {

    // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // when translatorViewModel.inputEnglishText().onNext("Dog"); // then testObserver.assertValueAt(testObserver.valueCount() - 1, "Dog translated"); } Starts recording…
  221. TestObserver: Recording started too late Malte Bucksch 22 @Test public

    void testTranslation() { // given TranslatorViewModel translatorViewModel = new TranslatorViewModelImpl(); // when translatorViewModel.inputEnglishText().onNext("Dog"); TestObserver<String> testObserver = translatorViewModel.outputGermanText().test(); // then testObserver.assertValueAt(testObserver.valueCount() - 1, "Dog translated"); } Starts recording…
  222. Training Agenda • Part 1: RxJava Background and Overview •

    Part 2: RxJava Basics • Part 3: RxJava Operators • Part 4: Example of a modern UI architecture with RxJava • Part 5: Testing with RxJava • Part 6: RxJava Advanced Malte Bucksch 1
  223. Operators for dealing with Side effects do.. • doOnComplete •

    doOnDispose • doOnEach • doOnError • doOnNext • doOnSubscribe • doOnTerminate … Malte Bucksch 3
  224. Example: Concating String Malte Bucksch 6 String separator = "

    "; Observable<String> concatString = Observable .just("Ich", "heiße", "Tom") … concatString.subscribe(System.out::print);
  225. Example: Concating String Malte Bucksch 7 String separator = "

    "; Observable<String> concatString = Observable .just("Ich", "heiße", "Tom") .reduce((s, s2) -> s + separator + s2) .toObservable(); concatString.subscribe(System.out::print);
  226. Example: Concating String Malte Bucksch 8 Observable<String> concatString = Observable

    .just("Ich", "heiße", "Tom") .compose(RxTransformers.concatStrings(" ")); concatString.subscribe(System.out::print);
  227. Hacking: Build a custom operator with “compose” for printing the

    state changes of an Observable exercise7_compose_and_sideeffects Malte Bucksch 11
  228. Sharing subscriptions with “share()” Open exercise8_share/ShareExercise and run the main

    function Look at the printed output: Do you notice something strange? Malte Bucksch 13
  229. Cold Observables Malte Bucksch 14 Observable<String> observable = Observable.just("A", "B",

    "C", "D", "E"); // observer 1 observable.subscribe(val -> { // "A", "B", "C", "D", "E" will be received in order }); // observer 2 observable.subscribe(val -> { // Again, "A", "B", "C", "D", "E" will be received in order });
  230. What will be printed? Malte Bucksch 21 System.out.println("Creating Observable."); Observable.<String>create(emitter

    -> { emitter.onNext("test"); emitter.onComplete(); }).subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(String value) { System.out.println("onNext(): " + value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { System.out.println("onComplete()"); } }); System.out.println("After subscribing."); Creating Observable. After subscribing onNext() - test onComplete() Creating Observable. onNext() - test onComplete() After subscribing Creating Observable. onNext() - test After subscribing onComplete() A B C
  231. What will be printed? Malte Bucksch 22 System.out.println("Creating Observable."); Observable.<String>create(emitter

    -> { emitter.onNext("test"); emitter.onComplete(); }).subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(String value) { System.out.println("onNext(): " + value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { System.out.println("onComplete()"); } }); System.out.println("After subscribing."); Creating Observable. After subscribing onNext() - test onComplete() Creating Observable. onNext() - test onComplete() After subscribing Creating Observable. onNext() - test After subscribing onComplete() A B C
  232. What will be printed? Malte Bucksch 23 Observable.<String>create(emitter -> {

    emitter.onNext("test"); emitter.onComplete(); }).subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(String value) { System.out.println("onNext(): " + value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { System.out.println("onComplete()"); } }); System.out.println("After subscribing."); “Creating Observable. onNext() - test onComplete() After subscribing”
  233. Looking back on what we achieved • Learned RxJava Basics

    as well as many advanced Rx-concepts Malte Bucksch 2
  234. Looking back on what we achieved • Learned RxJava Basics

    as well as many advanced Rx-concepts • Learned most important Rx-Operators Malte Bucksch 3
  235. Looking back on what we achieved • Learned RxJava Basics

    as well as many advanced Rx-concepts • Learned most important Rx-Operators • Learned how to write asynchronous code in Rx Malte Bucksch 4
  236. Looking back on what we achieved • Learned RxJava Basics

    as well as many advanced Rx-concepts • Learned most important Rx-Operators • Learned how to write asynchronous code in Rx • Learned how to build a User interface architecture with RxJava Malte Bucksch 5
  237. Looking back on what we achieved • Learned RxJava Basics

    as well as many advanced Rx-concepts • Learned most important Rx-Operators • Learned how to write asynchronous code in Rx • Learned how to build a User interface architecture with RxJava • Learned how to test asynchronous code with RxJava code Malte Bucksch 6
  238. Looking back on what we achieved • Learned RxJava Basics

    as well as many advanced Rx-concepts • Learned most important Rx-Operators • Learned how to write asynchronous code in Rx • Learned how to build a User interface architecture with RxJava • Learned how to test asynchronous code with RxJava code • Learned tricks to make your Rx-Code look more beautiful and robust Malte Bucksch 7
  239. Summary: RxJava - Advantages • makes managing asynchronous data flows

    easier • allows you to write declarative rather than imperative code • allows you to write similar code in different programming languages • makes your code more functional and predictable • makes testing of asynchronous code easier • Makes asynchronous error-handling easier • supplies many operators to solve problems more concisely • can make your application more fluent and performant by using lazy evaluation and simplifying parallelization Malte Bucksch 8
  240. Summary: RxJava - Disadvantages • Steep learning curve (sophisticated library

    that needs to be learned + needs time to think reactive/functional rather than imperative) • Adds a dependency which the whole project is based on • Debugging is sometimes less comfortable Malte Bucksch 9
  241. Getting clarity: Questions and Discussion Example topics: • Observable creation

    • Observable subscriptions • Observable operators • Async code and Multithreading • Single/Maybe/Completable/Subjects • Error handling • Side effects • Architecture with Rx • Testing (e.g. manipulating time with TestScheduler) Malte Bucksch 10
  242. More Resources The introduction to Reactive Programming you've been missing

    https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 Interactive Rx-Marbles Diagrams http://rxmarbles.com/ Great book about Rx (for free) http://www.introtorx.com/ Book: https://www.amazon.de/Learning-RxJava-Concurrent-responsive- applications/dp/1787120422/ref=sr_1_1?ie=UTF8&qid=1529678994&sr=8- 1&keywords=rxjava+nield More: https://github.com/ReactiveX/RxJava/wiki/Additional-Reading Malte Bucksch 12