Más contenido relacionado


Intro to Reactive Thinking and RxJava 2

  1. - Reactive Extensions first introduced by Microsoft in 2009 for .NET - Has been ported on most platforms and languages History
  2. Proved in production
  3. “Unless you can model the entire system of your app in a synchronous fashion, having a single asynchronous source will ultimately break the traditional imperative style of programming we’re used to.”
  4. Advantages - Simplifies the ability to chain async operations. - Surfaces errors sooner. - Easy threading - Helps reduce the need for state variables that can introduce bugs.
  5. Disadvantages - The API surface area is large. consequently, the learning curve is steep
  6. What is RxJava? RxJava is Reactive Extensions for the JVM - a library for composing asynchronous and event-based programs using Observable sequences for the Java VM
  7. What is RxJava? In other words we are pushing data instead of pulling it without worrying about threads. On top of that you are given an amazing toolbox of functions to combine create and filter the streams
  8. How to think in RxJava
  9. Should I use RxJava 2 instead of 1? YES! - Mar 2018 - end of RxJava 1 support - Better performance - Lower memory consumption - Can’t use null - Backpressure (Flowable)
  10. Iterable vs Observable, seems familiar? Event Iterable Observable retrieve data T next() onNext(T) discover error throw Exception onError(Exception) complete !hasNext() onCompleted() transform fromIterable() toList()
  11. Observables and Observers The basic building blocks of reactive code are Observables (Producer) and Observers (Consumer). The Observable object is the one who does the job. An Observer consumes the items emitted by the Observable. An Observable calls Observer#onNext() for every item, followed by either Observer#onComplete() or Observer#onError().
  12. Observables and Friends - Flowable: 0..N flows, supporting reactive streams and backpressure - Observable: 0..N flows, no backpressure - Single: a flow of exactly 1 item or am error - Completable: a flow without items but only a completion or error signal - Maybe: a flow with no items, exactly one item or an error
  13. Disposables Disposables represents the link between your Observable and your Subscriber Disposable d = Observable.timer(0, TimeUnit.SECONDS).subscribe(aLong -> {}); //Adding the disposable to CompositeDisposable disposables.add(d); //You can remove a disposable using delete method disposables.delete(d); //The container can be later reused disposables.clear(); //The container cannot be reused disposables.dispose();
  14. Creating Observable Let's take the most basic example to understand how this is structured. Observable.just(“Hello!”)
  15. Creating Observable from async (The ugly way) Observable<Movie> movieObservable = Observable.create( new ObservableOnSubscribe<Todo>() { @Override public void subscribe(ObservableEmitter<Movie> emitter) throws Exception { try { // Fetches Movie objects from the network, database, etc. List<Movie> movies = getMovies(); for (Movie movie : movies) { emitter.onNext(movie); } emitter.onComplete(); } catch (Exception e) { emitter.onError(e); } } }); When we want to create an Observable using async code
  16. Creating Observable using lambda Observable<Movie> movieObservable = Observable.create(emitter -> { try { // Fetches Movie objects from the network, database, etc. List<Movie> movies = getMovies(); for (Movie movie : movies) { emitter.onNext(movie); } emitter.onComplete(); } catch (Exception e) { emitter.onError(e); } }); Lambda expressions is only a “new” way of doing the same thing we always been able to do but in a cleaner and less wordy the new way of on how to use anonymous inner classes.
  17. Defining Observers Let's take the most basic example to understand how this is structured. movieObservable.subscribe(new Observer<String>() { @Override public void onNext(String s) { System.out.println("onNext: " + s); } @Override public void onCompleted() { System.out.println("done!"); } @Override public void onError(Throwable e) { } }); public interface Observer<T> { void onNext(T t); void onCompleted(); void onError(Throwable e); }
  18. Operators There is 248 operators we will focus on the common - map() - flatmap() - filter() - distinct() - take() - count()
  19. Operators - Map Transform the items emitted by an Observable by applying a function to each item
  20. Operators - Map - Example Observable.just("Hello!") .map(new Func1<String, String>() { @Override public String call(String s) { return s + " Dan"; } }) .subscribe(s -> System.out.println(s)); Observable.just("Hello!") .map(s -> s + " Dan") .subscribe(s -> System.out.println(s));
  21. Operators - Flatmap - Transforms the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable (no order)
  22. Operators - Flatmap - Example Observable.just("Hello!") .flatMap(new Func1<List<String>, Observable<String>>() { @Override public Observable<String> call(List<String> urls) { return Observable.from(urls); } }) .subscribe(url -> System.out.println(url)); Observable.just("Hello!") .flatMap(urls -> Observable.from(urls)) .subscribe(title -> System.out.println(title));
  23. Flatmap vs Map - Map returns an object of type T while FlatMap returns an Observable<T>. - FlatMap - It basically merges an observable sequence of observable sequences into a single observable sequence.
  24. Operators - Filter - Emits the same items it received, only if it passes the boolean check (predicate)
  25. Operators - Filter - Example Observable.just("Hello!") .flatMap(urls -> Observable.from(urls)) .flatMap(url -> getTitle(url)) .filter(title -> title != null) .subscribe(url -> System.out.println(url));
  26. Operators - Reduce - The Distinct operator filters an Observable by only allowing items through that have not already been emitted.
  27. Operators - Reduce - Example Observable.just("Hello!") .flatMap(urls -> Observable.from(urls)) .flatMap(url -> getTitle(url)) .distinct(title -> title.startsWith(“Hell”) .subscribe(url -> System.out.println(url));
  28. Operators - Take - Emits only the first n items emitted by an Observable
  29. Operators - Take - Example Observable.just("Hello!") .flatMap(urls -> Observable.from(urls)) .flatMap(url -> getTitle(url)) .filter(title -> title != null) .take(5) .subscribe(title -> System.out.println(title));
  30. Operators - Zip - Emits when it has all the values to zip
  31. Error handling - onError() is called if an exception is thrown at any time. - The operators do not have to handle the exception public interface Observer<T> { void onNext(T t); void onCompleted(); void onError(Throwable e); }
  32. Error Operators - onErrorResumeNext() - onErrorReturn() - onExceptionResumeNext() - retry() - retryWhen()
  33. Multithread like a BOSS Unbounded thread pool Schedulers.computation() Bounded thread pool with size up to the number of processors available.
  34. Multithread Example Observable.just("long", "longer", "longest") .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .map(String::length) .filter(length -> length == 6) .subscribe(length -> System.out.println("item length " + length));
  35. Multiple REST Calls Observable<JsonObject> userObservable = repo .create(User.class) .getUser(loginName) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()); Observable<JsonArray> eventsObservable = repo .create(Event.class) .listEvents(loginName) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()); Retrofit repo = new Retrofit.Builder() .baseUrl("") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); Let’s first setup two observables for the two network requests below:
  36. Zip magic Observable<UserAndEvents> combined =, eventsObservable, new Func2<JsonObject, JsonArray, UserAndEvents>() { @Override public UserAndEvents call(JsonObject jsonObject, JsonArray jsonElements) { return new UserAndEvents(jsonObject, jsonElements); } }); We use RxJava’s zip method to combine our two Observables and wait for them to complete before creating a new Observable.
  37. Consume response combined.subscribe(new Subscriber<UserAndEvents>() { ... @Override public void onNext(UserAndEvents o) { // You can access the results of the // two observabes via the POJO now } }); Finally let’s call the subscribe method on our new combined Observable:
  38. Login case // force-disable the button submitButton.setEnabled(false); emailChangeObservable = RxTextView.textChangeEvents(email); passwordChangeObservable = RxTextView.textChangeEvents(password); Observable.combineLatest(emailChangeObservable, passwordChangeObservable, (emailObservable, passwordObservable) -> { boolean emailCheck = emailObservable.text().length() >= 3; boolean passwordCheck = passwordObservable.text().length() >= 3; return emailCheck && passwordCheck; }).subscribe(aBoolean -> { submitButton.setEnabled(aBoolean); }); A common case that appears in almost every app that requires you to have an account is the Sign In screen. I wanted to set up form validation so that only when all fields are valid then a Sign In button would be enabled.
  39. Repository pattern example public Observable<List<Repository>> getRepositories() { Observable<List<Repository>> remote = getRemoteRepositories(); Observable<List<Repository>> local = getLocalRepositories(); return Observable.concat(local, remote); }
  40. What about Unit Testing?
  41. What about Testings? @Test public void shouldLoadTwoUsers() throw Exception { TestSubscriber<User> testSubscriber = new TestSubscriber<>(); databaseHelper.loadUser().subscribe(testSubscriber); testSubscriber.assertNoErrors(); testSubscriber.assertReceivedOnNext(Arrays.asList(user1, user2)) } TestSubscriber is a helper class provided by RxJava that we can use for unit testing, to perform assertions, inspect received events, or wrap a mocked Subscriber. @Test public void testValueCont() { Observable.just("Hello","RxJava","Testing").subscribe(wordListTestSubscriber); wordListTestSubscriber.assertValueCount(3); }
  42. Questions?Questions :)